C++笔记——unique_ptr智能指针
背景:在C++中,动态内存的管理通常是通过一对运算符new,在动态内存中为对象分配空间并返回该对象的指针,可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。在使用中容易出现问题,因为要保证在正确的时间释放内存是困难的。忘记释放会造成内存泄露。为了更安全的使用动态内存,C++11标准库提供两种智能指针来管理动态对象,shared_ptr和unique_ptr。
std::unique_ptr是C++11标准中用来取代std::auto_ptr的指针容器(在C++11中,auto_ptr被废弃)。它不能与其它unique_ptr类型的指针对象共享所指对象的内存。这种”所有权”仅能够通过标准库的move函数来转移。unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型。不支持普通的拷贝或赋值操作。
范例程序:
1、构造函数
// unique_ptr constructor example #include <iostream> #include <memory> int main () { std::default_delete<int> d; std::unique_ptr<int> u1; std::unique_ptr<int> u2 (nullptr); std::unique_ptr<int> u3 (new int); std::unique_ptr<int> u4 (new int, d); std::unique_ptr<int> u5 (new int, std::default_delete<int>()); std::unique_ptr<int> u6 (std::move(u5)); std::unique_ptr<int> u7 (std::move(u6)); std::unique_ptr<int> u8 (std::auto_ptr<int>(new int)); std::cout << "u1: " << (u1?"not null":"null") << '\n'; std::cout << "u2: " << (u2?"not null":"null") << '\n'; std::cout << "u3: " << (u3?"not null":"null") << '\n'; std::cout << "u4: " << (u4?"not null":"null") << '\n'; std::cout << "u5: " << (u5?"not null":"null") << '\n'; std::cout << "u6: " << (u6?"not null":"null") << '\n'; std::cout << "u7: " << (u7?"not null":"null") << '\n'; std::cout << "u8: " << (u8?"not null":"null") << '\n'; return 0; }
结果如下:
如果直接赋值,会报错。
2、析构函数
// unique_ptr destructor example #include <iostream> #include <memory> int main () { auto deleter = [](int*p){ delete p; std::cout << "[deleter called]\n"; }; std::unique_ptr<int,decltype(deleter)> foo (new int,deleter); std::cout << "foo " << (foo?"is not":"is") << " empty\n"; return 0; // [deleter called] }
输出:
注意:是return0之后,deleter被调用。
3、赋值运算法
// unique_ptr::operator= example #include <iostream> #include <memory> int main () { std::unique_ptr<int> foo; std::unique_ptr<int> bar; foo = std::unique_ptr<int>(new int (101)); // rvalue std::cout << "foo before: "; if (foo) std::cout << *foo << '\n'; else std::cout << "empty\n"; bar = std::move(foo); // using std::move std::cout << "foo after: "; if (foo) std::cout << *foo << '\n'; else std::cout << "empty\n"; std::cout << "bar: "; if (bar) std::cout << *bar << '\n'; else std::cout << "empty\n"; return 0; }
输出
注意:这里就能体现出unique的特点,只能指向一个对象,赋值用移动构造函数std::move()
4、get和release方法:get函数不会使unique_ptr释放指针的所有权(即,它仍然负责在某个时刻删除托管数据)。因此,该函数返回的值不应用于构造新的托管指针。
为了获得存储的指针并释放对其的所有权,请改为调用unique_ptr::release。
// unique_ptr::get vs unique_ptr::release #include <iostream> #include <memory> int main () { // foo bar p // --- --- --- std::unique_ptr<int> foo; // null std::unique_ptr<int> bar; // null null int* p = nullptr; // null null null foo = std::unique_ptr<int>(new int(10)); // (10) null null bar = std::move(foo); // null (10) null p = bar.get(); // null (10) (10) *p = 20; // null (20) (20) p = nullptr; // null (20) null foo = std::unique_ptr<int>(new int(30)); // (30) (20) null p = foo.release(); // null (20) (30) *p = 40; // null (20) (40) std::cout << "foo: "; if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n"; std::cout << "bar: "; if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n"; std::cout << "p: "; if (p) std::cout << *p << '\n'; else std::cout << "(null)\n"; std::cout << '\n'; delete p; // the program is now responsible of deleting the object pointed to by p // bar deletes its managed object automatically return 0; }
5、get_deleter方法
// unique_ptr deleter with state #include <iostream> #include <memory> class state_deleter { // a deleter class with state int count_; public: state_deleter() : count_(0) {} template <class T> void operator()(T* p) { std::cout << "[deleted #" << ++count_ << "]\n"; delete p; } }; int main () { state_deleter del; std::unique_ptr<int> p; // uses default deleter // alpha and beta use independent copies of the deleter: std::unique_ptr<int,state_deleter> alpha (new int); std::unique_ptr<int,state_deleter> beta (new int,alpha.get_deleter()); // gamma and delta share the deleter "del" (deleter type is a reference!): std::unique_ptr<int,state_deleter&> gamma (new int,del); std::unique_ptr<int,state_deleter&> delta (new int,gamma.get_deleter()); std::cout << "resetting alpha..."; alpha.reset(new int); std::cout << "resetting beta..."; beta.reset(new int); std::cout << "resetting gamma..."; gamma.reset(new int); std::cout << "resetting delta..."; delta.reset(new int); std::cout << "calling gamma/delta deleter..."; gamma.get_deleter()(new int); alpha.get_deleter() = state_deleter(); // a brand new deleter for alpha // additional deletions when unique_ptr objects reach out of scope // (in inverse order of declaration) return 0; }
输出:
6、reset方法
// unique_ptr::reset example #include <iostream> #include <memory> int main () { std::unique_ptr<int> up; // empty up.reset (new int); // takes ownership of pointer *up=5; std::cout << *up << '\n'; up.reset (new int); // deletes managed object, acquires new pointer *up=10; std::cout << *up << '\n'; up.reset(); // deletes managed object return 0; }
输出:
作者:水水滴答
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。