unique_ptr

发布时间 2023-03-26 13:12:28作者: Clemens

在头文件<memory>中定义。

std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。

在下列两者之一发生时用关联的删除器释放对象:

(1)销毁了管理的 unique_ptr 对象

struct B {
    virtual ~B() = default;
    virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B {
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }
    void bar() override { std::cout << "D::bar\n"; }
};
int main()
{
    auto del = [](D * p) {
        std::cout << "deleter called\n";
        delete  p;
    };
    std::unique_ptr<D, decltype(del)> p(new D(), del); 
    //输出:
    //D::D
    //deleter called
    //D::~D
}

 (2)通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。

使用operator=:

std::unique_ptr<D> p(new D());
// std::unique_ptr<D> q = p; //错误:不能复制
std::unique_ptr<D> q = std::move(p);
// output:
//D::D
//D::~D

 使用reset

struct B {
    virtual ~B() = default;
    virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B {
    D() { std::cout << "D::D\n"; }
    D(std::string s) : str(s) { std::cout << "D::D " << s << std::endl; }
    ~D() { std::cout << "D::~D " << str << std::endl; }
    void bar() override { std::cout << "D::bar\n"; }
    std::string str = "";
};
int main()
{
    auto del = [](D * p) {
        std::cout << "deleter called " << p->str << std::endl;;
        delete  p;
    };
    std::unique_ptr<D, decltype(del)> p(new D("d1"), del);
    p.reset(new D("d2"));
}

输出:

D::D d1
D::D d2
deleter called d1
D::~D d1
deleter called d2
D::~D d2

unique_ptr 亦可以不占有对象,该情况下称它为空 (empty)

std::unique_ptr 有两个版本:

1) 管理单个对象(例如以 new 分配)
2) 管理动态分配的对象数组(例如以 new[] 分配)

类满足可移动构造 (MoveConstructible) 可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 可复制赋值 (CopyAssignable) 的要求。

Deleter 必须是函数对象 (FunctionObject) 或到函数对象 (FunctionObject) 的左值引用或到函数的左值引用,可以 unique_ptr<T, Deleter>::pointer 类型参数调用

注解

只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。

std::unique_ptr 常用于管理对象的生存期,包含:

  • 正常退出和经由异常退出都可保证删除,提供异常安全,给处理拥有动态生存期的对象的类和函数
  • 传递独占的拥有动态生存期的对象的所有权到函数
  • 从函数获得独占的拥有动态生存期对象的所有权
  • 作为具移动容器的元素类型,例如保有指向动态分配对象的指针的 std::vector (例如,若想要多态行为)

若 T 是某基类 B 的派生类,则 std::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用 B 的 operator delete ,这导致未定义行为,除非 B 的析构函数为虚函数。

 

release

pointer release() noexcept;

若存在,则释放被管理对象的所有权。调用release()后,再调用get() 返回 nullptr 。调用方负责删除该对象。

注意:这里的释放不是销毁对象,只是将其指向的对象释放出去。

返回值:指向被管理对象的指针,或若无被管理对象则为 nullptr ,即调用前 get() 会返回的值。

int main()
{
    auto del = [](D * p) {
        std::cout << "deleter called " << p->str << std::endl;;
        delete  p;
    };
    std::unique_ptr<D, decltype(del)> p(new D("d1"), del);
    D *q = p.release();    
    std::cout << p.get() << std::endl;    //输出: 0
    std::cout << q->str << std::endl;    //输出: d1
    delete q;
}

 

D::D d1
0
d1
D::~D d1

 

swap

void swap( unique_ptr& other ) noexcept;

交换 *this 和另一个 unique_ptr 对象 other 的托管对象和关联删除器。

int main()
{
    std::unique_ptr<D> p(new D("d1"));
    std::unique_ptr<D> q(new D("d2"));
    p.swap(q);
    std::cout << p->str << " " << q->str << std::endl;
}

输出:

D::D d1
D::D d2
d2 d1
D::~D d1
D::~D d2