- C++智能指针之unique_ptr
- unique_ptr篇
- 简介
- 成员函数
- 构造函数
- 析构函数
- get
- get_deleter
- release
- reset
- swap
- operator=
- operator bool
- 练习
unique_ptr是一种定义在
constexpr unique_ptr() noexcept; // 默认构造函数1 std::unique_ptru1;
constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {} // 默认构造函数2:传入空指针
std::unique_ptr u2 (nullptr);
explicit unique_ptr (pointer p) noexcept; // 传入其它指针 std::unique_ptru3 (new int);
unique_ptr (pointer p,
typename conditional::value,D,const D&> del) noexcept; // 传入指针和左值删除器
std::default_delete d;
std::unique_ptr u4 (new int, d);
unique_ptr (pointer p,typename remove_reference::type&& del) noexcept; // 传入指针和右值删除器 std::unique_ptr u5 (new int, std::default_delete ());
unique_ptr (unique_ptr&& x) noexcept; // 调用move构造 std::unique_ptru6 (std::move(u5));
templateunique_ptr (unique_ptr&& x) noexcept; // 调用move右值构造 std::unique_ptr u7 (std::move(u6));// u6->nullptr u7-> u6
templateunique_ptr (auto_ptr&& x) noexcept; // 通过移动 auto_ptr 构造 std::unique_ptr u8 (std::auto_ptr (new int))
unique_ptr (const unique_ptr&) = delete; // 拷贝构造 int *p = new int; *p = 10; std::unique_ptr析构函数u9 (p);
如果对象是空(nullptr)则析构无效:
// ~unique_ptr(); // unique_ptr destructor example #includeget#include int main () { auto deleter = [](int*p){ delete p; std::cout << "[deleter called]n"; }; std::unique_ptr foo (new int,deleter); std::cout << "foo " << (foo?"is not":"is") << " emptyn"; return 0; // [deleter called] }
返回存储的指针。
pointer get() const noexcept;
#includeget_deleter#include int main() { std::unique_ptr foo(new int); int *p = nullptr; p = foo.get(); *p = 10; std::cout << foo.get() << ":" << *foo << "n"; std::cout << p << ":" << *p << "n"; return 0; }
返回对象存储的删除器。
deleter_type& get_deleter() noexcept; const deleter_type& get_deleter() const noexcept;
#includerelease#include class myDeleter { int m_count; public: myDeleter() :m_count(0){} template void operator()(T* p) { // 重载操作符() if (p) { delete p; p = nullptr; std::cout << "deleter #" << ++m_count << 'n'; } } }; int main() { { myDeleter del; std::unique_ptr one(new int, del); // 值 std::unique_ptr two(new int, one.get_deleter()); // 值 std::unique_ptr three(new int, one.get_deleter()); // 引用 std::unique_ptr four(new int, del); // 值 *one = 69; std::cout << one.get() << ":" << *one << "n"; one.reset(); // count = 1 *two = 96; std::cout << two.get() << ":" << *two << "n"; two.reset(); // count = 1 *three = 36; std::cout << three.get() << ":" << *three << "n"; three.reset(); // count = 2 *four = 63; std::cout << four.get() << ":" << *four << "n"; four.reset(); // count = 1 } std::cin.get(); return 0; }
释放对象存储的指针和对象所有权,并返回该指针。
pointer release() noexcept;
#includereset#include int main() { std::unique_ptr foo(new int); int* p = foo.release(); *p = 10; std::cout << foo.get() << "n"; std::cout << p << ":" << *p << "n"; delete p; // 注意:foo对象释放所有权后不再自动释放. return 0; }
如果p是空,销毁该对象管理的内存;
如果p不是空,销毁该对象管理的内存,并且该对象重新获取p的所有权;
void reset (pointer p = pointer()) noexcept;
#includeswap#include int main() { std::unique_ptr foo(new int); *foo = 10; { std::cout << "before foo calls reset:" << foo.get() << " : " << *foo << "n"; // 有效地址 foo.reset(); //删除该指针管理的对象 std::cout << "after foo calls reset:" << foo.get() << "n"; // 无效地址 foo.reset(new int); //获取新的指针 *foo = 11; std::cout << "before foo calls reset(p):" << foo.get() << ":" << *foo << "n"; // 有效地址 } std::cin.get(); return 0; }
交互俩个对象的所有权(包括deleter)
void swap (unique_ptr& x) noexcept;
#includeoperator=#include int main() { { std::unique_ptr foo(new int); std::unique_ptr bar(new int); *foo = 66; *bar = 99; std::cout << "before foo calls swap:" << foo.get() << " : " << *foo << "n"; std::cout << "before bar calls swap:" << bar.get() << " : " << *bar << "n"; foo.swap(bar); std::cout << "after foo calls swap:" << foo.get() << " : " << *foo << "n"; std::cout << "after bar calls swap:" << bar.get() << " : " << *bar << "n"; } std::cin.get(); return 0; }
获取对象的所有权和删除器(右值将被析构,所有权都转移,就像调用reset()方法一样)。
unique_ptr& operator= (unique_ptr&& x) noexcept; // 移动赋值 unique_ptr& operator= (nullptr_t) noexcept; // 赋值nullptr templateunique_ptr& operator= (unique_ptr&& x) noexcept; // 类型转换赋值 unique_ptr& operator= (const unique_ptr&) = delete; // 拷贝赋值
#includeoperator bool#include int main() { { std::unique_ptr foo; std::unique_ptr boo(nullptr); // 赋值nullptr foo = std::unique_ptr (new int(96)); // 类型转换赋值 std::cout << "[foo]" << foo.get() << ':' << *foo << 'n'; boo = std::move(foo); // 移动赋值 std::cout << "[boo]" << boo.get() << ':' << *boo << 'n'; } std::cin.get(); return 0; }
检测管理对象的指针是否为空(get()!=nullptr)。
explicit operator bool() const noexcept;
#include练习#include int main() { { std::unique_ptr foo(new int); std::unique_ptr bar; std::cout << "foo is " << (foo ? "not empty!n" : "emptyn"); std::cout << "bar is " << (bar ? "not empty!n" : "emptyn"); } std::cin.get(); return 0; }
#include#include using namespace std; class TestPtr { public: TestPtr() :name("default") { std::cout << __func__ << " : " << name << "n"; } TestPtr(const char *_name) :name(_name) { std::cout << __func__ << " : " << name << "n"; } ~TestPtr() { std::cout << __func__ << " : " << name << "n"; } void PrintName(void) { std::cout << "Name:" << name << "n"; } private: std::string name; }; void Test() { TestPtr* p4(nullptr); int i = 1; { std::unique_ptr p3(new TestPtr("p3")); { std::unique_ptr p0(new TestPtr("p0")); // 方式一 std::cout << '[' << i++ << "] p0:" << p0.get() << "n"; std::unique_ptr p1 = std::move(p0); // 移动p0的对象到p1, 内存不释放 std::cout << '[' << i++ << "] after p0 calls move :" << p0.get() << "n"; // 无效地址:唯一指针,转移后为本身指向nullptr std::cout << '[' << i++ << "] after p0 is moved to p1:" << p1.get() << "n"; // 有效地址:指向p0原来指向的地址 p1.reset(); // 主动释放p1的内存 std::cout << '[' << i++ << "] after reset p1:" << p1.get() << "n"; // 无效地址:主动调用析构释放内存 std::unique_ptr p2 = std::make_unique ("p2"); // 方式二 std::cout << '[' << i++ << "] p2:" << p2.get() << "n"; p4 = p3.release(); // 释放p3对象存储内存所有权,返回给p4 p3 = std::move(p2); // 移动p2的对象到p3, 对象的内存不释放,p3的对象内存自动释放 std::cout << '[' << i++ << "] after p2 calls move :" << p2.get() << "n"; // 无效地址:唯一指针,转移后为本身指向nullptr std::cout << '[' << i++ << "] after p2 is moved to p3:" << p3.get() << "n"; // 有效地址:指向p2原来指向的地址 } // p3 内存不释放 p3->PrintName(); // name:p2 p4->PrintName(); // name: p3 } // 离开作用域后析构函数自动释放 p3的内存 if (p4) { std::cout << "p4 is not empty ptr, need manual delete it!n"; delete p4; // 手动释放p3对象的内存,不释放就内存泄露 p4 = nullptr; } else { std::cout << "p4 is empty ptr,good!n"; } } int main() { Test(); std::cin.get(); return 0; }



