unique_ptr 与原始指针的不同行为

Different behaviour of unique_ptr vs raw pointer

我正在努力理解原始指针和 unique_ptr 的行为差异。我有 class A 和变量 xclass B 以及指向 A:

实例的指针
class A
{
public:
    int x;
};

A::A(int y) : x(y)
{
}

class B
{
public:
    B(A &);
    A *p;
};

B::B(A &a)
{
    p = &a;
}

这符合我的预期:

int main()
{
    A a(2);
    B b(a);
    cout << a.x << " " << b.p->x << endl;
    a.x = 4;
    cout << a.x << " " << b.p->x << endl; 
}

给予

2 2
4 4

将原始指针更改为 std::unique_ptr 会得到不同的结果:

class A
{
public:
    int x;
};

A::A(int y) : x(y)
{
}

class B
{
public:
    B(A &);
    std::unique_ptr<A> p;
};

B::B(A &a)
{
    p = std::make_unique<A>(a);
}

给予

2 2
4 2

我是否从根本上误解了 unique_ptrs 的某些内容?

make_unique 创建一个新对象,unique_pt 可以独占访问该对象。因此,在第二个示例中,您有两个对象,而不是一个,当您在第一个对象中设置更改 a.x 的值时,它不会影响 unique_ptr.[=14= 持有的另一个对象]

尝试从智能指针版本读取以下表达式:

std::make_unique<A>(a);

"制作 唯一 A 来自 a"(没有提到指针!

结果是unique_ptr,但是在读取表达式时,将其读取为使(类型为)模板参数。函数参数是构造函数的参数。在这种情况下,您正在从一个 A 对象创建一个 A 对象,它会拉入复制构造函数。

一旦您了解智能指针版本正在创建一个新的 A 对象(而您的原始指针版本则不会),您的结果应该是有意义的。


“唯一A”中的“唯一”可能很难理解。将其视为一个其他人无法拥有的对象。它可能是另一个对象的副本,但是,作为unique_ptr的角色,它是你的副本,你的负责清理干净之后,就没有别人的了。你的宝贝,你不会分享的(c.f。std::make_shared)。

请注意,局部变量(如 main 函数中的 a )是编译器的责任,因此它没有资格成为 unique_ptr 的对象点(或任何智能指针,就此而言)。

一个独特的指针需要拥有它指向的任何东西。您的代码可以工作 - 只需替换 unique_ptr 类型并保持其他一切不变(没有 make_unique)。但它会有未定义的行为,因为您将创建一个指向其他地方拥有的对象的唯一指针。

为了比较苹果与苹果,原始指针代码应为 p=new A(a);。这就是 make_unique 所做的。