How to: Create and Use unique_ptr Instances
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr, passed by value to a function (unless it is a modifiable rvalue), or used in any Standard Template Library (STL) algorithm that requires copies to be made. A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to a new unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic. Therefore, when you need a smart pointer for a plain C++ object, use unique_ptr.
The following diagram illustrates the transfer of ownership between two unique_ptr instances.
unique_ptr is defined in the <memory> header in the STL. It is exactly is efficient as a raw pointer and can be used in STL containers. The addition of unique_ptr instances to STL containers is efficient because the move constructor of the unique_ptr eliminates the need for a copy operation.
Example
The following example shows how to create unique_ptr instances and pass them between functions.
unique_ptr<Song> SongFactory(std::wstring artist, std::wstring title)
{
// Implicit move operation into the variable that stores the result.
return unique_ptr<Song>(new Song(artist, title));
}
void MakeSongs()
{
// Create a new unique_ptr with a new object.
unique_ptr<Song> pSong = unique_ptr<Song>(new Song(L"Mr. Children", L"Namonaki Uta"));
// Use the unique_ptr
vector<wstring> titles;
titles.push_back(pSong->title);
// Move raw pointer from one unique_ptr to another.
unique_ptr<Song> pSong2 = std::move(pSong);
// Obtain unique_ptr from function that returns rvalue reference.
auto pSong3 = SongFactory(L"Michael Jackson", L"Beat It");
}
These examples demonstrate this basic characteristic of unique_ptr: it can be moved, but not copied. "Moving" transfers ownership to a new unique_ptr and resets the old unique_ptr.
The following example shows how to create unique_ptr instances and use them in a vector.
void SongVector()
{
vector<unique_ptr<Song>> v;
// Create a few new unique_ptr<Song> instances
// and add them to vector using implicit move semantics.
v.push_back(unique_ptr<Song>(new Song(L"B'z", L"Juice")));
v.push_back(unique_ptr<Song>(new Song(L"Namie Amuro", L"Funky Town")));
v.push_back(unique_ptr<Song>(new Song(L"Kome Kome Club", L"Kimi ga Iru Dake de")));
v.push_back(unique_ptr<Song>(new Song(L"Ayumi Hamasaki", L"Poker Face")));
// Pass by reference to lambda body.
for_each(v.begin(), v.end(), [] (const unique_ptr<Song>& p)
{
wcout << L"Artist: " << p->artist << L"Title: " << p->title << endl;
});
}
In the for_each loop, notice that the unique_ptr is passed by reference in the lambda expression. If you try to pass by value here, the compiler will throw an error because the unique_ptr copy constructor is disabled.
The following example shows how to initialize a unique_ptr that is a class member.
class MyClass
{
private:
// MyClass owns the unique_ptr.
unique_ptr<ClassFactory> factory;
public:
// Initialize by invoking the unique_ptr move constructor.
MyClass() : factory ( unique_ptr<ClassFactory>(new ClassFactory()))
{
}
void MakeClass()
{
factory->DoSomething();
}
};