
一、unique_ptr 概述
① unique_ptr 的特点
- unique_ptr 独享它指向的对象,也就是说,同时只有一个 unique_ptr 指向同一个对象,当这个 unique_ptr 被销毁时,指向的对象也随即被销毁。这也是它和 shared_pt r不一样的地方,它不需要做引用计数,也不可以被第二个人引用,只有它自己。
② unique_ptr 的用途
- 作为一个类的成员变量,这个变量只在本类使用,不会被赋值给其他类,也不会作为参数传递给某个函数;
- 在一个函数作为局部变量,使用完就不用再管,函数结束,自动释放托管资源。
③ unique_ptr 原理
- 构造时传入托管对象的指针,析构时 delete 对象,这是为了要对得其智能指针的名号,即主动删除托管对象;
- 禁用赋值函数,这是为了要唯一性,那就禁用赋值,不能再让别人引用它。那么怎么实现呢?很简单,把两种赋值函数,都设置为 delete,如下所示:
unique_ptr(const unique_ptr<T>&) noexcept = delete;unique_ptr& operator = (const unique_ptr&) noexcept = delete;
- 使用“=delete”修饰,表示函数被定义为 deleted,也就意味着这个成员函数不能再被调用,否则编译就会出错。当然,虽然赋值禁用了,但是愿意交出控制权,交给赋值的人,那还是可以允许的。
unique_ptr(unique_ptr&& move) noexcept {std::cout << "construct for unique_ptr&&" << std::endl;move.swap(*this);}unique_ptr& operator=(unique_ptr&& move) noexcept {move.swap(*this);return *this;}
- 参数 move 的类型,是一个右值引用,其实就是 std::move 的返回值,如下所示:
unique_ptr<Test> tPtr1(new Test());
unique_ptr<Test> tPtr3(std::move(tPtr1));
- 这种情况下,是可以编译过的,只不过,tPtr1 的资源,如其成员变量将无法再调用,调用的话就崩溃,因为它已经全部交给 tPtr3。
二、自定义实现
#include <utility>
#include<iostream>
template<typename T>
class unique_ptr {
private:T * ptr_resource = nullptr;public:explicit unique_ptr(T* raw_resource) noexcept : ptr_resource(std::move(raw_resource)) {}unique_ptr(std::nullptr_t) : ptr_resource(nullptr) {}unique_ptr() noexcept : ptr_resource(nullptr) {}~unique_ptr() noexcept {delete ptr_resource;}unique_ptr(const unique_ptr<T>&) noexcept = delete;unique_ptr& operator = (const unique_ptr&) noexcept = delete;public:unique_ptr(unique_ptr&& move) noexcept {std::cout << "construct for unique_ptr&&" << std::endl;move.swap(*this);}unique_ptr& operator=(unique_ptr&& move) noexcept {std::cout << "operator= for unique_ptr&&" << std::endl;move.swap(*this);return *this;}explicit operator bool() const noexcept {return this->ptr_resource;}T* release() noexcept {return std::exchange(ptr_resource, nullptr);}T* get() const noexcept {return ptr_resource;}void swap(unique_ptr<T>& resource_ptr) noexcept {std::swap(ptr_resource, resource_ptr.ptr_resource);}void reset(T* resource_ptr) noexcept(false) {if (resource_ptr == nullptr)throw std::invalid_argument("An invalid pointer was passed, resources will not be swapped");delete ptr_resource;ptr_resource = nullptr;std::swap(ptr_resource, resource_ptr);}
public:T * operator->() const noexcept {return this->ptr_resource;}T& operator*() const noexcept {return *this->ptr_resource;}
};
#include "UniquePtr.h"
class Test {
public:Test() {std::cout << "Test class construct" << std::endl;}~Test() {std::cout << "Test class destruct" << std::endl;}void printSomething() {std::cout << "Test printSomething " << std::endl;}void printResource() {std::cout << "Test printResource " << a << std::endl;}int getResource() {return a;}private:int a = 10;
};
class PUser {
public:PUser() {pTest.reset(new Test());std::cout << "PUser construct " << std::endl;}~PUser() {std::cout << "PUser destruct" << std::endl;}void userTest() {std::cout << "userTest " << pTest->getResource() << std::endl;}private:unique_ptr<Test> pTest;
};
int main(int argc, char* argv[]) {unique_ptr<Test> tPtr1(new Test());unique_ptr<Test> tPtr3(std::move(tPtr1));unique_ptr<Test> tPtr4 = std::move(tPtr3);tPtr1->printSomething(); PUser* pUser = new PUser();pUser->userTest();return 0;
}