为什么不能从unique_ptr构造weak_ptr?

ada*_*603 50 c++ smart-pointers shared-ptr weak-ptr unique-ptr

如果我理解正确,a weak_ptr不会增加托管对象的引用计数,因此它不代表所有权.它只是让您访问一个对象,其生命周期由其他人管理.所以我真的不明白为什么一个weak_ptr不能用a构建unique_ptr,而只能用a 构建shared_ptr.

有人能简单解释一下吗?

Dav*_*rtz 33

如果你考虑一下,weak_ptr必须引用除了对象本身之外的东西.那是因为对象可以不再存在(当没有更强的指针时),weak_ptr仍然必须引用包含对象不再存在的信息的东西.

有了a shared_ptr,那就是包含引用计数的东西.但是使用a unique_ptr,没有引用计数,因此没有包含引用计数的东西,因此当对象消失时没有任何东西可以继续存在.所以没有什么weak_ptr可以参考.

也没有理智的方式来使用这样的weak_ptr.要使用它,您必须有一些方法来保证在您使用它时不会破坏对象.这很容易shared_ptr- 这就是它的shared_ptr作用.但是你如何做到这一点unique_ptr呢?你显然不能拥有其中的两个,并且其他东西必须已经拥有该对象,否则它将被破坏,因为你的指针很弱.

  • 并且C ++试图避免不必要的开销不会给控制块的动态分配(可能会负担一个公共引用计数)(分配shared_ptrs的方式)造成的unique_ptrs负担。 (2认同)

Dav*_*aim 16

std::weak_ptr除非你将其转换为无法使用std::shared_ptr的手段lock().如果标准允许你建议,那意味着你需要将std :: weak_ptr转换为唯一才能使用它,违反唯一性(或重新发明std::shared_ptr)

为了说明,请看两段代码:

std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);

{
*(weak.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared  to keep it alive
}
Run Code Online (Sandbox Code Playgroud)

现在提出你的建议:

std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);

{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it! 
}
Run Code Online (Sandbox Code Playgroud)

有人说,你可能会建议只有一个unique_ptr,你仍然可以解除引用weak_ptr(不创建另一个unique_ptr)然后没有问题.但那么unique_ptrshared_ptr一个参考之间有什么区别?或者更多,unique_ptr通过使用获得的常规和C指针有什么区别get

weak_ptr它不是"一般非拥有资源",它有非常具体的工作 - 主要目标weak_ptr是防止循环指向shared_ptr哪些会导致内存泄漏.还有其他任何东西都需要用普通的unique_ptrshared_ptr.


Mot*_*tti 12

A shared_ptr基本上有两部分:

  1. 指向的对象
  2. 引用计数对象

一旦引用计数降至零,就删除对象(#1).

现在weak_ptr需要能够知道对象是否仍然存在.为了做到这一点,它必须能够看到引用计数对象(#2),如果它不为零,它可以shared_ptr为对象创建一个(通过递增引用计数).如果计数为零,则返回空shared_ptr.

现在考虑何时可以删除引用计数对象(#2)?我们必须等到没有shared_ptrOR weak_ptr对象引用它.为此目的,引用计数对象包含两个引用计数,一个引用和一个引用.引用计数对象仅在其计数均为零时才会被删除.这意味着只有在所有弱引用消失后才能释放部分内存(这意味着隐藏的缺点make_shared).

TL;博士; weak_ptr取决于弱引用计数是其中的一部分shared_ptr,不能weak_ptr没有a shared_ptr.

  • 实际上,`weak_ptr`是引用计数对象的`shared_ptr`. (2认同)

Ulr*_*rdt 8

从概念上讲,没有什么能阻止一个实现,其中weak_ptr只提供访问权限,而unique_ptr控制生命周期.但是,有一些问题:

  • unique_ptr不使用引用计数开头.添加用于管理弱引用的管理结构是可能的,但需要额外的动态分配.因为unique_ptr应该避免对原始指针的任何(!)运行时开销,所以这种开销是不可接受的.
  • 为了使用a引用的对象weak_ptr,你需要从中提取一个"真实"引用,它将首先验证指针是否先过期,然后给你这个真正的引用(shared_ptr在本例中为a).这意味着您突然有一个对应该唯一拥有的对象的第二个引用,这是一个错误的配方.这不能通过返回一个混合的半强指针来解决,该指针只会暂时延迟对指针的可能破坏,因为你也可以存储那个,同时击败背后的想法unique_ptr.

只是想知道,你想用weak_ptr这里解决什么问题?


小智 8

看起来每个人都在这里写关于 std::weak_ptr 但不是关于弱指针概念,我相信这是作者所要求的

我认为没有人提到为什么标准库不为 unique_ptr 提供weak_ptr。弱指针 CONCEPT 并不否认 unique_ptr 的使用。弱指针仅是对象已被删除的信息,因此它不是魔术,而是非常简单的广义观察者模式。

这是因为线程安全性和与shared_ptr的一致性。

您只是无法保证您的weak_ptr(从其他线程上存在的unique_ptr 创建的)在调用指向对象的方法期间不会被破坏。因为weak_ptr需要和std::shared_ptr保持一致,保证线程安全。您可以实现weak_ptr,它可以与unique_ptr一起正常工作,但只能在同一线程上 - 在这种情况下,锁定方法是不必要的。您可以检查 base::WeakPtr 和 base::WeakPtrFactory 的铬源 - 您可以通过 unique_ptr 自由使用它。Chromium 弱指针代码很可能基于最后一个成员销毁 - 您需要将工厂添加为最后一个成员,之后我相信 WeakPtr 会被告知对象删除(我不是 100% 确定) - 所以它看起来并不很难实施。

总的来说,使用带有弱指针概念的 unique_ptr 是可以的,恕我直言。


The*_*ant 5

没有人提到问题的性能方面,所以让我扔掉0.02美元.

weak_ptr必须以某种方式知道相应的shared_ptrs 何时已经超出范围并且指向的对象已被解除分配和销毁.这意味着shared_ptr需要以weak_ptr某种方式将破坏传递给同一个对象.这有一定的成本 - 例如,需要更新全局哈希表,weak_ptr从中获取地址(或者nullptr如果对象被销毁).

这还涉及锁定多线程环境,因此对于某些任务来说可能太慢.

但是,目标unique_ptr是提供零成本 RAII风格的抽象类.因此,它不应该招致比的任何其他成本delete荷兰国际集团(或delete[]荷兰国际集团)的动态分配的对象.例如,通过执行锁定或以其他方式保护的哈希表访问所施加的延迟可以与解除分配的成本相当,但是在这种情况下这是不希望的unique_ptr.