【问题标题】:Two std::unique_ptr pointing to the same object – undefined behaviour?两个 std::unique_ptr 指向同一个对象——未定义的行为?
【发布时间】:2019-10-07 12:57:20
【问题描述】:

假设如下代码:

T* t = new T();
std::unique_ptr<T> p1(t);
std::unique_ptr<T> p2(t);

显然,现在两个std::unique_ptrs 指向同一个对象。这种状态本身是否已经是未定义的行为?我在标准中找不到合适的提示,所以到目前为止我会回答“不”,但希望得到再次保证。

旁注:这个问题不是关于稍后通过双重删除产生的未定义行为,这可以通过指针release()在正确的时间发送其内容来避免......

【问题讨论】:

  • 我不是委员会成员,所以我不能肯定,但draft 表示要求是unique_ptr 必须拥有在构造函数完成后传递给它的指针.因为这将使p1p2 都拥有所有权,所以我会说,是的,这是未定义的行为
  • 是双重免费的UB。这是无法通过我的审查的危险代码。
  • @Jarod42 完全同意危险代码。试验想法以获得this problem的解决方案(或者即使extract可用,避免一次又一次地重新安排地图),想法会如果已创建副本,则在析构函数中释放智能指针是一个单独的结构......但在我看来,真正的解决方案是,如果 真的 是性能问题,则不在地图中使用智能指针那个案子……

标签: c++ language-lawyer


【解决方案1】:

从技术上讲,在您执行导致双重删除的操作之前,没有 UB。 std::unique_ptr does not state that the pointer should not already be owned, 的构造函数,所以从最严格的意义上讲,两个对象所拥有的指针并不是未定义的行为

也就是说,从语义上讲,代码不正确,不应该这样做。您违反了std::unique_ptr 提供的唯一所有权保证,这意味着您必须非常小心如何使用这些对象,以免陷入双重删除状态。

【讨论】:

  • 我不同意,它明确指出它应该在事后拥有。我承认这可能是标准中的一个缺陷,但对我来说 owns 意味着单一所有权。因此,一旦p2 完成构造 IMO,行为就未定义。我怀疑这是模棱两可的,因为实际行为取决于删除器。
  • @Mgetz 后面的std::shared_ptr 使用了完全相同的措辞。显然,该标准并不意味着“拥有”的独占或共享所有权......
  • @Aconcagua 是的,这会变得很复杂,因为从技术上讲,对于内部引用计数的对象 unique_ptr 可以在没有 UB insofar 的情况下使用,因为使用了非默认删除器。我个人认为这种 specific 情况是 UB,因为它为同一个对象创建了两个默认删除器。因此,从技术上讲,编译器可以在 P2 的最终构造时开始时间旅行,因为即使 P1 或 P2 在作用域结束之前获得.release,它也会产生一种情况,如果作用域在该点退出,可能会发生这种情况。不管怎样,我不是委员会成员。
  • @Mgetz 只有在存在导致双重删除的实际路径时才能进行时间​​旅行。如果 OP 很小心,并确保在任何代码路径上都不会发生双重删除,那么就没有 UB,也不会发生时间旅行。它违背了使用unique_ptr 的全部目的,因此不应该这样做,但不幸的是,它可以这样做。话虽如此,该标准确实应该更新以要求指针没有已经拥有,以明确表示不应进行此使用。
  • @NathanOliver 在这种情况下,如果在这些构造和.release 之间的这种特定情况下发生任何非noexcept 调用,这将IMO 触发UB,因为这表明范围可以退出并因此触发UB .这就是我试图传达的。也就是说,具有不同删除器的不同构造函数是完全不同的情况。 IMO 应更新标准以指定 default_deleter 只能与非先前拥有的指针一起使用。但我怀疑这是隐含的效果。
猜你喜欢
  • 2020-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多