跳到主要内容

std::unique_ptr<T,Deleter>::unique_ptr

声明

// 1)
constexpr unique_ptr() noexcept;
constexpr unique_ptr( std::nullptr_t ) noexcept;
// 2)
constexpr explicit unique_ptr( pointer p ) noexcept;
// 3)
constexpr unique_ptr( pointer p, /* see below */ d1 ) noexcept;
// 4)
constexpr unique_ptr( pointer p, /* see below */ d2 ) noexcept;
// 5)
constexpr unique_ptr( unique_ptr&& u ) noexcept;
// 6)
template< class U, class E >
constexpr unique_ptr( unique_ptr<U, E>&& u ) noexcept;

描述

1)

构造一个不拥有任何东西的std::unique_ptr。值初始化存储的指针和存储的删除器。要求DeleterDefaultConstructible,并且构造不抛出异常。这些重载仅在std::is_default_constructible<Deleter>::valuetrueDeleter*不是*指针类型时才参与重载解析。

2)

构造一个拥有pstd::unique_ptr,用p初始化存储的指针,并值初始化存储的删除器。要求DeleterDefaultConstructible,并且构造不抛出异常。此重载仅在std::is_default_constructible<Deleter>::valuetrueDeleter*不是*指针类型时才参与重载解析。

此构造函数不被类模板参数推导选择。(自 C++17 起)

3-4)

构造一个std::unique_ptr对象,它拥有p,用p初始化存储的指针,并根据D是否为引用类型来初始化删除器D

  • 如果D为非引用类型A,则签名如下:

    unique_ptr(pointer p, const A& d) noexcept;  (1)  (要求Deleter是nothrow-CopyConstructible)
    unique_ptr(pointer p, A&& d) noexcept;    (2)  (要求Deleter是nothrow-MoveConstructible)

  • 如果D为左值引用类型A&,则签名如下:

    unique_ptr(pointer p, A& d) noexcept;  (1)
    unique_ptr(pointer p, A&& d) = delete;  (2)

  • 如果D为左值引用类型const A&,则签名如下:

    unique_ptr(pointer p, const A& d) noexcept;  (1)
    unique_ptr(pointer p, const A&& d) = delete;  (2)

在所有情况下,删除器都从std::forward<decltype(d)>(d)初始化。这些重载仅在std::is_constructible<D, decltype(d)>::valuetrue时才参与重载解析。

这两个构造函数不被类模板参数推导选择。(自 C++17 起)

2-4)

在数组的特化版本中,其行为与主模板中采用指针参数的构造函数相同,但它们额外地仅在以下任一情况成立时才参与重载解析

  • U与指针类型相同,或者
  • Ustd::nullptr_t,或者
  • pointerelement_type*类型相同,并且U为某种指针类型V*,使得V(*)[]可以隐式转换为element_type(*)[]

5)

构造一个unique_ptr,通过将所有权从u转移到*this,并在u中存储null指针。此构造函数仅在std::is_move_constructible<Deleter>::valuetrue时才参与重载解析。如果Deleter不是引用类型,则要求它是nothrow-MoveConstructible(如果Deleter是引用,则在移动构造后get_deleter()u.get_deleter()引用相同的值)

6)

构造一个unique_ptr,通过将所有权从u转移到*this,其中u使用指定的删除器(E)进行构造。这取决于E是否为引用类型,如下所示

  • 如果E为引用类型,则此删除器从u的删除器复制构造(要求此构造不抛出)
  • 如果E为非引用类型,则此删除器从u的删除器移动构造(要求此构造不抛出)

此构造函数仅在以下所有条件为真时才参与重载解析

  • unique_ptr<U, E>::pointer可以隐式转换为pointer
  • U不是数组类型
  • 要么Deleter是引用类型且ED类型相同,要么Deleter不是引用类型且E可以隐式转换为D

7)

构造一个unique_ptr,其中存储的指针用u.release()初始化,存储的删除器值初始化。此构造函数仅在U*可以隐式转换为T*Deleterstd::default_delete<T>类型相同时才参与重载解析。

参数

p - 要管理的对象指针
d1,d2 - 用于销毁对象的删除器
u - 另一个要从中获取所有权的智能指针

备注

与使用重载(2)结合new相比,使用std::make_unique<T>通常是更好的选择。(自 C++14 起)

std::unique_ptr<Derived>可以隐式转换为std::unique_ptr<Base>,通过重载(6)(因为管理指针和std::default_delete都可以隐式转换)

由于默认构造函数是constexpr,静态unique_ptrs在静态非局部初始化期间被初始化,早于任何动态非局部初始化开始。这使得在任何静态对象的构造函数中使用unique_ptr是安全的。

没有从指针类型进行类模板参数推导,因为无法区分从数组和非数组形式的new获得的指针。(自 C++17 起)

示例

#include <iostream>
#include <memory>

struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};

struct D { // deleter
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(Foo* p) const {
std::cout << "D is deleting a Foo\n";
delete p;
};
};

int main()
{
std::cout << "Example constructor(1)...\n";
std::unique_ptr<Foo> up1; // up1 is empty
std::unique_ptr<Foo> up1b(nullptr); // up1b is empty

std::cout << "Example constructor(2)...\n";
{
std::unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
} // Foo deleted

std::cout << "Example constructor(3)...\n";
D d;
{ // deleter type is not a reference
std::unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
}
{ // deleter type is a reference
std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
}

std::cout << "Example constructor(4)...\n";
{ // deleter is not a reference
std::unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
}

std::cout << "Example constructor(5)...\n";
{
std::unique_ptr<Foo> up5a(new Foo);
std::unique_ptr<Foo> up5b(std::move(up5a)); // ownership transfer
}

std::cout << "Example constructor(6)...\n";
{
std::unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D is moved

std::unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D is copied
}

#if (__cplusplus < 201703L)
std::cout << "Example constructor(7)...\n";
{
std::auto_ptr<Foo> up7a(new Foo);
std::unique_ptr<Foo> up7b(std::move(up7a)); // ownership transfer
}
#endif

std::cout << "Example array constructor...\n";
{
std::unique_ptr<Foo[]> up(new Foo[3]);
} // three Foo objects deleted
}
结果
Example constructor(1)...
Example constructor(2)...
Foo ctor
~Foo dtor
Example constructor(3)...
Foo ctor
D copy ctor
D is deleting a Foo
~Foo dtor
Foo ctor
D is deleting a Foo
~Foo dtor
Example constructor(4)...
Foo ctor
D move ctor
D is deleting a Foo
~Foo dtor
Example constructor(5)...
Foo ctor
~Foo dtor
Example constructor(6)...
Foo ctor
D copy ctor
D move ctor
Foo ctor
D non-const copy ctor
D is deleting a Foo
~Foo dtor
D is deleting a Foo
~Foo dtor
Example constructor(7)...
Foo ctor
~Foo dtor
Example array constructor...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor

std::unique_ptr<T,Deleter>::unique_ptr

声明

// 1)
constexpr unique_ptr() noexcept;
constexpr unique_ptr( std::nullptr_t ) noexcept;
// 2)
constexpr explicit unique_ptr( pointer p ) noexcept;
// 3)
constexpr unique_ptr( pointer p, /* see below */ d1 ) noexcept;
// 4)
constexpr unique_ptr( pointer p, /* see below */ d2 ) noexcept;
// 5)
constexpr unique_ptr( unique_ptr&& u ) noexcept;
// 6)
template< class U, class E >
constexpr unique_ptr( unique_ptr<U, E>&& u ) noexcept;

描述

1)

构造一个不拥有任何东西的std::unique_ptr。值初始化存储的指针和存储的删除器。要求DeleterDefaultConstructible,并且构造不抛出异常。这些重载仅在std::is_default_constructible<Deleter>::valuetrueDeleter*不是*指针类型时才参与重载解析。

2)

构造一个拥有pstd::unique_ptr,用p初始化存储的指针,并值初始化存储的删除器。要求DeleterDefaultConstructible,并且构造不抛出异常。此重载仅在std::is_default_constructible<Deleter>::valuetrueDeleter*不是*指针类型时才参与重载解析。

此构造函数不被类模板参数推导选择。(自 C++17 起)

3-4)

构造一个std::unique_ptr对象,它拥有p,用p初始化存储的指针,并根据D是否为引用类型来初始化删除器D

  • 如果D为非引用类型A,则签名如下:

    unique_ptr(pointer p, const A& d) noexcept;  (1)  (要求Deleter是nothrow-CopyConstructible)
    unique_ptr(pointer p, A&& d) noexcept;    (2)  (要求Deleter是nothrow-MoveConstructible)

  • 如果D为左值引用类型A&,则签名如下:

    unique_ptr(pointer p, A& d) noexcept;  (1)
    unique_ptr(pointer p, A&& d) = delete;  (2)

  • 如果D为左值引用类型const A&,则签名如下:

    unique_ptr(pointer p, const A& d) noexcept;  (1)
    unique_ptr(pointer p, const A&& d) = delete;  (2)

在所有情况下,删除器都从std::forward<decltype(d)>(d)初始化。这些重载仅在std::is_constructible<D, decltype(d)>::valuetrue时才参与重载解析。

这两个构造函数不被类模板参数推导选择。(自 C++17 起)

2-4)

在数组的特化版本中,其行为与主模板中采用指针参数的构造函数相同,但它们额外地仅在以下任一情况成立时才参与重载解析

  • U与指针类型相同,或者
  • Ustd::nullptr_t,或者
  • pointerelement_type*类型相同,并且U为某种指针类型V*,使得V(*)[]可以隐式转换为element_type(*)[]

5)

构造一个unique_ptr,通过将所有权从u转移到*this,并在u中存储null指针。此构造函数仅在std::is_move_constructible<Deleter>::valuetrue时才参与重载解析。如果Deleter不是引用类型,则要求它是nothrow-MoveConstructible(如果Deleter是引用,则在移动构造后get_deleter()u.get_deleter()引用相同的值)

6)

构造一个unique_ptr,通过将所有权从u转移到*this,其中u使用指定的删除器(E)进行构造。这取决于E是否为引用类型,如下所示

  • 如果E为引用类型,则此删除器从u的删除器复制构造(要求此构造不抛出)
  • 如果E为非引用类型,则此删除器从u的删除器移动构造(要求此构造不抛出)

此构造函数仅在以下所有条件为真时才参与重载解析

  • unique_ptr<U, E>::pointer可以隐式转换为pointer
  • U不是数组类型
  • 要么Deleter是引用类型且ED类型相同,要么Deleter不是引用类型且E可以隐式转换为D

7)

构造一个unique_ptr,其中存储的指针用u.release()初始化,存储的删除器值初始化。此构造函数仅在U*可以隐式转换为T*Deleterstd::default_delete<T>类型相同时才参与重载解析。

参数

p - 要管理的对象指针
d1,d2 - 用于销毁对象的删除器
u - 另一个要从中获取所有权的智能指针

备注

与使用重载(2)结合new相比,使用std::make_unique<T>通常是更好的选择。(自 C++14 起)

std::unique_ptr<Derived>可以隐式转换为std::unique_ptr<Base>,通过重载(6)(因为管理指针和std::default_delete都可以隐式转换)

由于默认构造函数是constexpr,静态unique_ptrs在静态非局部初始化期间被初始化,早于任何动态非局部初始化开始。这使得在任何静态对象的构造函数中使用unique_ptr是安全的。

没有从指针类型进行类模板参数推导,因为无法区分从数组和非数组形式的new获得的指针。(自 C++17 起)

示例

#include <iostream>
#include <memory>

struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};

struct D { // deleter
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(Foo* p) const {
std::cout << "D is deleting a Foo\n";
delete p;
};
};

int main()
{
std::cout << "Example constructor(1)...\n";
std::unique_ptr<Foo> up1; // up1 is empty
std::unique_ptr<Foo> up1b(nullptr); // up1b is empty

std::cout << "Example constructor(2)...\n";
{
std::unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
} // Foo deleted

std::cout << "Example constructor(3)...\n";
D d;
{ // deleter type is not a reference
std::unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
}
{ // deleter type is a reference
std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
}

std::cout << "Example constructor(4)...\n";
{ // deleter is not a reference
std::unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
}

std::cout << "Example constructor(5)...\n";
{
std::unique_ptr<Foo> up5a(new Foo);
std::unique_ptr<Foo> up5b(std::move(up5a)); // ownership transfer
}

std::cout << "Example constructor(6)...\n";
{
std::unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D is moved

std::unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D is copied
}

#if (__cplusplus < 201703L)
std::cout << "Example constructor(7)...\n";
{
std::auto_ptr<Foo> up7a(new Foo);
std::unique_ptr<Foo> up7b(std::move(up7a)); // ownership transfer
}
#endif

std::cout << "Example array constructor...\n";
{
std::unique_ptr<Foo[]> up(new Foo[3]);
} // three Foo objects deleted
}
结果
Example constructor(1)...
Example constructor(2)...
Foo ctor
~Foo dtor
Example constructor(3)...
Foo ctor
D copy ctor
D is deleting a Foo
~Foo dtor
Foo ctor
D is deleting a Foo
~Foo dtor
Example constructor(4)...
Foo ctor
D move ctor
D is deleting a Foo
~Foo dtor
Example constructor(5)...
Foo ctor
~Foo dtor
Example constructor(6)...
Foo ctor
D copy ctor
D move ctor
Foo ctor
D non-const copy ctor
D is deleting a Foo
~Foo dtor
D is deleting a Foo
~Foo dtor
Example constructor(7)...
Foo ctor
~Foo dtor
Example array constructor...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor