标签:
unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。我们建议你将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使用 unique_ptr,而当构造 unique_ptr 时,可使用make_unique Helper 函数。
std::unique_ptr实现了独享所有权的语义。一个非空的std::unique_ptr总是拥有它所指向的资源。转移一个std::unique_ptr将会把所有权也从源指针转移给目标指针(源指针被置空)。拷贝一个std::unique_ptr将不被允许,因为如果你拷贝一个std::unique_ptr,那么拷贝结束后,这两个std::unique_ptr都会指向相同的资源,它们都认为自己拥有这块资源(所以都会企图释放)。因此std::unique_ptr是一个仅能移动(move_only)的类型。当指针析构时,它所拥有的资源也被销毁。默认情况下,资源的析构是伴随着调用std::unique_ptr内部的原始指针的delete操作的。
下图演示了两个 unique_ptr 实例之间的所有权转换。
unique_ptr 在 STL 的 <memory> 标头中定义。它与原始指针一样有效,并可用于 STL 容器。将 unique_ptr 实例添加到 STL 容器很有效,因为通过unique_ptr 的移动构造函数,不再需要进行复制操作。
以下示例演示如何创建 unique_ptr 实例并在函数之间传递这些实例。
unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title) { // Implicit move operation into the variable that stores the result. return make_unique<Song>(artist, title); } void MakeSongs() { // Create a new unique_ptr with a new object. auto song = make_unique<Song>(L"Mr. Children", L"Namonaki Uta"); // Use the unique_ptr. vector<wstring> titles = { song->title }; // Move raw pointer from one unique_ptr to another. unique_ptr<Song> song2 = std::move(song); // Obtain unique_ptr from function that returns by value. auto song3 = SongFactory(L"Michael Jackson", L"Beat It"); }
以下示例演示如何创建 unique_ptr 实例并在向量中使用这些实例。
void SongVector() { std::vector<unique_ptr<Song>> songs; // Create a few new unique_ptr<Song> instances // and add them to vector using implicit move semantics. songs.push_back(make_unique<Song>(L"B‘z", L"Juice")); songs.push_back(make_unique<Song>(L"Namie Amuro", L"Funky Town")); songs.push_back(make_unique<Song>(L"Kome Kome Club", L"Kimi ga Iru Dake de")); songs.push_back(make_unique<Song>(L"Ayumi Hamasaki", L"Poker Face")); // Pass by const reference when possible to avoid copying. for (const auto& song : songs) { std::cout << L"Artist: " << song->artist << L" Title: " << song->title << endl; } }
在 range for 循环中,注意 unique_ptr 通过引用来传递。如果你尝试通过此处的值传递,由于删除了 unique_ptr 复制构造函数,编译器将引发错误。
以下示例演示如何初始化类成员 unique_ptr。
class MyClass { private: // MyClass owns the unique_ptr. unique_ptr<ClassFactory> factory; public: // Initialize by using make_unique with ClassFactory default constructor. MyClass() : factory ( make_unique<ClassFactory>()) {
} void MakeClass() { factory->DoSomething(); } };
可使用 make_unique 将 unique_ptr 创建到数组,但无法使用 make_unique 初始化数组元素。
// Create a unique_ptr to an array of 5 integers. auto p = std::make_unique<int[]>(5); // Initialize the array. for (int i = 0; i < 5; ++i) { p[i] = i; std::cout << p[i] << std::endl; }
举例:
{ //创建一个指向int的空指针 std::unique_ptr<int> fPtr1; std::unique_ptr<int> fPtr2(new int(4)); auto fPtr3 = std::make_unique<int>(); //fPtr2释放指向对象的所有权,并且被置为nullptr std::cout << "fPtr2 release before:" << fPtr2.get() << std::endl; int *pF = fPtr2.release(); std::cout << "fPtr2 release before:" << fPtr2.get() << " and pF value:" << *pF << std::endl; //所有权转移,转移后fPtr3变为空指针 std::cout << "move before fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl; fPtr1 = std::move(fPtr3); std::cout << "move after fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl; std::cout << "move before fPtr1 address:" << fPtr1.get() << std::endl; fPtr1.reset(); std::cout << "move after fPtr1 address:" << fPtr1.get() << std::endl; }
输出:
fPtr2 release before:00EFB120
fPtr2 release before:00000000 and pF value:4
move before fPtr1 address:00000000 fPtr3 address:00EFEC60
move after fPtr1 address:00EFEC60 fPtr3 address:00000000
move before fPtr1 address:00EFEC60
move after fPtr1 address:00000000
创建与释放
#include <iostream> #include <memory> #include <stdlib.h> struct Foo { Foo() { std::cout << "Foo::Foo\n"; } ~Foo() { std::cout << "Foo::~Foo\n"; } void bar() { std::cout << "Foo::bar\n"; } }; void f(const Foo &) { std::cout << "f(const Foo&)\n"; } struct D { void operator()(Foo* foo) { std::cout << "D operator()" << std::endl; delete foo; } }; void TestAutoDestroy() { //1. 普通的new对象. std::cout << "TestDestroy...................." << std::endl; { std::unique_ptr<Foo> p1(new Foo); } //2. 普通的new[]对象. { std::unique_ptr<Foo[]> p2(new Foo[4]); } //3. 自定义的deleter. { std::unique_ptr<Foo, D> p3(new Foo); } } void TestOwner() { std::cout << "TestOwner...................." << std::endl; //1. new object. std::unique_ptr<Foo> p1(new Foo); // p1 owns Foo if (p1) p1->bar(); { std::unique_ptr<Foo> p2(std::move(p1)); // now p2 owns Foo f(*p2); p1 = std::move(p2); // ownership returns to p1 p2->bar(); std::cout << "destroying p2...\n"; } p1->bar(); } void TestArrayOwner() { std::cout << "TestArrayOwner...................." << std::endl; //1. new[] object. std::unique_ptr<Foo[]> p1(new Foo[4]); // p1 owns Foo if (p1) p1[0].bar(); { std::unique_ptr<Foo[]> p2(std::move(p1)); // now p2 owns Foo f(p2[0]); p1 = std::move(p2); // ownership returns to p1 p2[0].bar(); std::cout << "destroying p2...\n"; } p1[0].bar(); } int main() { TestAutoDestroy(); TestOwner(); TestArrayOwner(); }
输出:
TestDestroy.................... Foo::Foo Foo::~Foo Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::Foo D operator() Foo::~Foo TestOwner.................... Foo::Foo Foo::bar f(const Foo&) Foo::bar destroying p2... Foo::bar Foo::~Foo TestArrayOwner.................... Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::bar f(const Foo&) Foo::bar destroying p2... Foo::bar Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo
标签:
原文地址:http://www.cnblogs.com/DswCnblog/p/5628195.html
这些示例说明了 unique_ptr 的基本特征:可移动,但不可复制。“移动”将所有权转移到新 unique_ptr 并重置旧 unique_ptr。