Suppose we have the hypothetical case where pointers are used for all types of variables. More exactly, we have the following procedure to read the elements of a one-dimensional array:
void leer_arreglo(int *&v)
{
int *i = new int;
for (*i = 0; *i < dim_v; (*i)++)
{
cout << "Elemento " << *i + 1 << ": ";
cin >> v[*i];
}
delete i;
}
As you can see, even the variable i
, which is only used to traverse the elements of the array, is declared as a pointer to int
, and as such, at the end of the procedure the memory must be freed manually.
What would be the most reasonable solution to keep the variable i
within the scope of the loop for
while avoiding manually freeing the memory allocated for that pointer?
My first attempt was the following:
void leer_vector(int *&v)
{
for (int *i = new int(0); *i < dim_v; (*i)++)
{
cout << "Elemento " << *i + 1 << ": ";
cin >> v[*i];
}
delete i;
}
The problem is that an error is generated at the moment of reaching the instruction delete i;
because said variable no longer exists outside the scope of the for
.
Then the following occurred to me:
void leer_vector(int *&v)
{
for (int *i = new int(0); *i < dim_v; (*i)++)
{
cout << "Elemento " << *i + 1 << ": ";
cin >> v[*i];
delete i;
}
}
However, I seriously doubt that the above is a good idea because on each iteration I am freeing the allocated memory.
I didn't really know what to do until I discovered smart pointers ( thanks Paula_plus_plus) and then I got the following code:
void leer_vector(int *&v)
{
for (auto i = make_unique<int>(); *i < dim_v; (*i)++)
{
cout << "Elemento " << *i + 1 << ": ";
cin >> v[*i];
}
}
Nice, right? The variable i
is in scope for
and we don't have to worry about manually freeing the allocated memory. So my question arises: is this a valid use of smart pointers?
I ask this question because despite reviewing some SO links where it is analyzed in which cases this type of pointers should be used, I am still not entirely clear if in my particular case the last piece of code that I put is a correct solution and acceptable.
Thank you in advance for your comments and/or answers.
Clear: the code compiles, runs, and does not produce run-time errors or memory leaks; so it is a valid usage.
Another thing is that the code you have shown as an example is an intelligent use of smart pointers, which in my opinion: it is not; for instance:
The raison d'être of smart pointers is precisely to free the memory allocated to them, so if you wanted the allocated memory not to be freed: a smart pointer should not be your choice.
Smart pointers were introduced in the C++11 standard, although in C++ there was already an attempt to standardize the RAII 1 idiom over 2 pointers before the 2011 standard, that attempt was very limited and inflexible, so it was decided to deprecate it and develop three types of smart pointers:
Single pointer (
std::unique_ptr
).It wraps a pointer that conceptually will have a single owner, when the pointer is no longer used or is reassigned, the resources it was managing are released; It is possible to move the pointer between different scopes:
The one
std::unique_ptr
created insidedame_dato
does not release the assigned pointer when it goes out of scope, but rather causes it to change owner, the previous owner being the functiondame_dato
and the new owner being the caller.Shared pointer (
std::shared_ptr
).Wraps a pointer that will conceptually have multiple owners, the number of owners of the pointer is remembered as an atomic counter handled by the smart pointer itself; growing when gaining an owner and decreasing when losing it. When the owners counter reaches zero, the resources that the pointer was handling will be released, it is also possible to move the pointer between different scopes and if instead of moving it is copied, the owners counter will be updated, this can be costly at the level of process because handling such a counter involves several security checks. The following code:
It would produce the following output:
Weak pointer (
std::weak_ptr
).It wraps a pointer that conceptually it will not own, any use of the pointer requires blocking it which will return a shared pointer, it allows to know if the object it points to exists through the function
std::weak_ptr::expired
.When to use smart pointers?
The single pointer will be used when we know that the pointed resource will have a single owner, the shared pointer will be used when the pointed resource has multiple owners, and the weak pointer will be used to claim the use of shared pointers without (other than temporarily) owning them. .
std::auto_ptr
, deprecated in C++11 and removed from the standard in C++17.