当原始指针传递到其构造函数时,unique_ptr 正在复制

Pis*_*ers 1 c++ c++11 c++14

我试图了解现代 C++ 中唯一指针的工作原理。

当我浏览文档(cppreference 和其他文档)时,我能够理解这unique_ptr将转移所有权而不是共享它。但我不明白为什么unique_ptr在使用传递到其构造函数的原始指针时表现得很奇怪。

例如:

#include <iostream>
#include <memory>

class foo{
    int x;
public:
    foo(): x(0) {}
    foo(int a): x(a) {}
    foo(const foo& f): x(f.x) {}
};

int main(){
    foo *ptr = new foo(5);
    std::unique_ptr<foo> uptr(ptr);
    std::cout << ptr << "\n";
    std::cout << uptr.get() << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

0x5c7bc80
0x5c7bc80
Run Code Online (Sandbox Code Playgroud)

查询:

  • 原始指针是否被传递到复制构造函数中?复制构造函数不是被删除了吗(=delete)?为什么原始指针打印的地址与 相同unique_ptr
  • 这是设计缺陷吗unique_ptr
  • 我该如何克服这个问题?
  • 有什么用std::make_unique()?我尝试更改线路std::unique_ptr<foo> uptr(ptr);std::unique_ptr<foo> uptr(std::make_unique<foo>(*ptr));没有任何改变。

Rem*_*eau 6

原始指针是否被传递到复制构造函数中?

不是复制构造函数,不(需要另一个unique_ptr作为输入)。相反,原始指针被传递给转换构造函数,特别是在本例中:

explicit unique_ptr( pointer p ) noexcept;
Run Code Online (Sandbox Code Playgroud)

复制构造函数不是被删除了吗(=delete)?

是的。但这段代码没有调用复制构造函数。

为什么原始指针打印与 相同的地址unique_ptr

因为它unique_ptr只是将输入指针按原样复制到其自己的内部成员指针中,从而获得所指向的对象的所有权。您正在打印两个指针的值,它们具有相同的值,因为它们指向内存中的同一个对象。

这是设计缺陷吗unique_ptr

不。

我该如何克服这个问题?

什么问题?这里没有问题。其unique_ptr行为符合设计。

有什么用std::make_unique()

为了更有效地分配内存,请在该内存中构造一个对象,并使用 new 获取该内存的所有权unique_ptr,所有这些都在一个操作中完成。

我尝试更改线路std::unique_ptr<foo> uptr(ptr);std::unique_ptr<foo> uptr(std::make_unique<foo>(*ptr));没有任何改变。

应该有。

该表达式std::make_unique<foo>(*ptr)正在创建一个与所指向的foo对象分离的新对象。ptr它将把取消引用的*ptr对象传递给新foo对象的复制构造函数。

然后,在表达式 中std::unique_ptr<foo> uptr(...);uptr移动返回unique_ptrmake_unique(),它指向新foo对象。所以uptr现在拥有该foo对象。

随后,您的 2 个打印应该输出不同的值,因为ptruptr指向不同的foo对象。

请注意,在这种情况下,您将泄漏所指向的foo对象,因为没有人取得该对象的所有权。所以你有责任手动进行它。ptrunique_ptrdelete

这段代码:

foo *ptr = new foo(5);
std::unique_ptr<foo> uptr(ptr);
Run Code Online (Sandbox Code Playgroud)

可以改为这样:

std::unique_ptr<foo> uptr = std::make_unique<foo>(5);
Run Code Online (Sandbox Code Playgroud)

或者:

auto uptr = std::make_unique<foo>(5);
Run Code Online (Sandbox Code Playgroud)

std::make_unique()分配并构造其模板参数中指定的类型,将输入参数传递给该对象的构造函数。