【问题标题】:Different behaviour of unique_ptr vs raw pointerunique_ptr 与原始指针的不同行为
【发布时间】:2021-03-18 06:59:48
【问题描述】:

我很难理解原始指针和 unique_ptr 的行为差异。我有 class A 和一个变量 x 和 class 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 的某些内容?

【问题讨论】:

  • 原始指针可以指向它不拥有的东西。 (根据一些现代 C++ 约定,这是首选的习惯用法。)唯一指针拥有它所指向的东西。所以它有自己的副本。
  • p = std::make_unique&lt;A&gt;(a); 是new 的替代品。而且你不能正确地让unique_ptr指向一个引用,因为它在析构函数中调用delete(除非你用自定义析构函数创建一个,但是你为什么要这样做呢?)。

标签: c++ pointers stl unique-ptr


【解决方案1】:

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

【讨论】:

  • 对。您可以从原始指针构造 unique_ptr,就像构造任何其他对象一样。 make_unique 是一个特殊的助手,它创建一个由唯一指针管理的新对象。
  • 谢谢。有没有办法获得所需的行为(没有原始指针)?或者这整个方法只是实现结果的糟糕方法?
  • 您的程序在堆栈上分配了 a,但无法在堆栈上创建指向对象的智能指针。否则,您可以重新安排程序以使用 shared_pointer,并在 main 中使用 make_shared 进行分配,而不仅仅是声明。
  • 我不认为你应该害怕使用本机指针来使一个对象引用另一个对象,而这两个对象都没有管理另一个对象的存储。
  • @operator 在询问如何获得所需的行为之前,您可能想说明所需的行为是什么。 (从代码中猜测规格是不可靠的。)回到你的目标,写下需求,也许可以用你失败的尝试开始一个新的问题,以说明你认为你可能会如何实现目标。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    std::make_unique&lt;A&gt;(a);

    “制作一个独特的 A来自a”(没有提到指针!)

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

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


    “唯一A”中的“唯一”可能很难理解。将其视为其他人无法声称的对象。它可能是另一个对象的副本,但是,作为unique_ptr 的角色,它是您的 副本,您 有责任在之后进行清理,而不是其他人的.你的宝贝,你不会分享的(c.f. std::make_shared)。

    请注意,局部变量(如main 函数中的a)是编译器的职责,因此它不能成为unique_ptr 指向的对象(或任何智能指针,例如那件事)。

    【讨论】:

      猜你喜欢
      • 2015-10-01
      • 2017-07-05
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 2021-10-28
      相关资源
      最近更新 更多