Of course, it could be possible that you really want to do something like statement #1. The assignment is unsafe only if you use the abandoned smart pointer in an unsmart manner, such as dereferencing it. But you could safely reuse the pointer by assigning a new value to it. C++ has a standard library function called std::move() that lets you assign one unique_ptr to another. Here is an example using the previously defined demo() function, which returns a unique_ptr
using namespace std;
unique_ptr
ps1 = demo("Uniquely special");
ps2 = move(ps1); // enable assignment
ps1 = demo(" and more");
cout << *ps2 << *ps1 << endl;
You may be wondering how unique_ptr, unlike auto_ptr, is able to discriminate between safe and possibly unsafe uses. The answer is that it uses the C++11 additions of move constructors and rvalue references, as discussed in Chapter 18.
Also unique_ptr has another advantage over auto_ptr. It has a variant that can be used with arrays. Remember, you must pair delete with new and delete [] with new []. The auto_ptr template uses delete, not delete [], so it can only be used with new, not with new []. But unique_ptr has a new[], delete[] version:
std::unique_ptr< double[]>pda(new double(5)); // will use delete []
Caution
You should use an auto_prt or shared_ptr object only for memory allocated by new, not for memory allocated by new []. You should not use auto_ptr, shared_ptr, or unique_ptr for memory not allocated via new or, in the case of unique_ptr, via new or new[].
Selecting a Smart Pointer
Which pointer type should you use? If the program uses more than one pointer to an object, shared_ptr is your choice. For instance, you may have an array of pointers and use some auxiliary pointers to identify particular elements, such as the largest and the smallest. Or you could have two kinds of objects that contain pointers to the same third object. Or you might have an STL container of pointers. Many of the STL algorithms include copy or assignment operations that will work with shared_ptr but not with unique_ptr (you’ll get a compiler warning) or auto_ptr (you’ll get undefined behavior). If your compiler doesn’t offer shared_ptr, you can get a version from the Boost library.
If the program doesn’t need multiple pointers to the same object, unique_ptr works. It’s a good choice for the return type for a function that returns a pointer to memory allocated by new. That way, ownership is transferred to the unique_ptr assigned the return value, and that smart pointer takes on the responsibility of calling delete. You can store unique_ptr objects in an STL container providing you don’t invoke methods or algorithms, such as sort(), that copy or assign one unique_ptr to another. For example, assuming the proper includes and using statements, code fragments like the following could be used in a program:
unique_ptr
{
return unique_ptr
}
void show(unique_ptr
{
cout << *a << ' ';
}
int main()
{
...
vector
for (int i = 0; i < vp.size(); i++)
vp[i] = make_int(rand() % 1000); // copy temporary unique_ptr
vp.push_back(make_int(rand() % 1000)) // ok because arg is temporary
for_each(vp.begin(), vp.end(), show); // use for_each()
...
}
The call to push_back() works because it passes a temporary unique_ptr to be assigned to a unique_ptr in vp. Also note the for_each() statement would fail if show() were passed an object by value instead of by reference because then it would be necessary to initialize pi to a nontemporary unique_ptr from vp, which isn’t allowed. As mentioned before, the compiler will catch attempts to use unique_ptr inappropriately.
You can assign a unique_ptr to shared_ptr under the same conditions that you can assign one unique_ptr to another—the source has to be an rvalue. As previously, in the following code make_int() is a function with a unique_ptr
unique_ptr
shared_ptr
shared_ptr
The shared_ptr template includes an explicit constructor for converting an rvalue unique_ptr to a shared_ptr. The shared_ptr takes over ownership of the object previously owned by the unique_ptr.
You would use auto_ptr in the same situation as unique_ptr, but the latter is preferred. If your compiler doesn’t provide unique_ptr, you might consider the BOOST library scoped_ptr, which is similar.
The Standard Template Library