与原始指针兼容的(shared_ptr + weak_ptr)设计 [英] Design of (shared_ptr + weak_ptr) compatible with raw pointers

查看:87
本文介绍了与原始指针兼容的(shared_ptr + weak_ptr)设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++ 11中,有std::shared_ptr + std::weak_ptr组合.尽管非常有用,但是它有一个令人讨厌的问题:您无法轻易地从原始指针构造shared_ptr .由于此缺陷,此类智能指针通常变得病毒式":人们开始完全避免使用原始指针和引用,并在整个代码中仅使用shared_ptr和weak_ptr智能指针.因为无法将原始引用传递给需要智能指针的函数.

In C++11 there is std::shared_ptr + std::weak_ptr combo. Despite being very useful, it has a nasty issue: you cannot easily construct shared_ptr from a raw pointer. As a result of this flaw, such smart pointers usually become "viral": people start to completely avoid raw pointers and references, and use exclusively shared_ptr and weak_ptr smart pointers all over the code. Because there is no way to pass a raw reference into a function expecting a smart pointer.

另一方面,有boost::intrusive_ptr.它等效于std::shared_ptr,并且可以很容易地从原始指针构造,因为引用计数器包含在对象中.不幸的是,它没有弱伴侣,因此没有办法拥有非所有者引用,您可以检查这些引用是否无效.实际上,有人认为 intrusive_ptr的弱伴侣是不可能的.

On the other hand, there is boost::intrusive_ptr. It is equivalent to std::shared_ptr and can easily be constructed from raw pointer, because reference counter is contained within the object. Unfortunately, there is no weak_ptr companion to it, so there is no way to have non-owning references which you could check for being invalid. In fact, some believe that weak companion for intrusive_ptr is impossible.

现在有std::enable_shared_from_this,它直接在您的课程中嵌入了weak_ptr ,以便您可以构造shared_ptr从指针到对象.但是有一个小的限制(至少必须存在一个shared_ptr),并且它仍然不允许明显的语法:std::shared_ptr(pObject).

Now, there is std::enable_shared_from_this, which embeds a weak_ptr directly into your class, so that you could construct shared_ptr from pointer to object. But there is small limitation (at least one shared_ptr must exist), and it still does not allow the obvious syntax: std::shared_ptr(pObject).

此外,还有一个std::make_shared,它在单个内存块中分配引用计数器和用户对象.这非常接近intrusive_ptr的概念,但是可以独立于引用计数块来销毁用户的对象.而且,此概念有一个不可避免的缺点:只有在所有weak_ptr-s都消失了之后,才会释放整个内存块(可能很大).

Also, there is a std::make_shared, which allocates reference counters and the user's object in a single memory chunk. This is very close to the concept of intrusive_ptr, but the user's object can be destroyed independently of the reference counting block. Also, this concept has an inevitable drawback: the whole memory block (which can be large) is deallocated only when all weak_ptr-s are gone.

主要问题是:如何创建一对shared_ptr/weak_ptr,它们将同时具有std::shared_ptr/std::weak_ptrboost::intrusive_ptr的优点?

The main question is: how to create a pair of shared_ptr/weak_ptr, which would have the benefits of both std::shared_ptr/std::weak_ptr and boost::intrusive_ptr?

尤其是:

  1. shared_ptr对对象的共享所有权进行建模,即,当指向该对象的最后一个shared_ptr被销毁时,该对象才被销毁.
  2. weak_ptr不会对对象的所有权建模,可以用于解决循环依赖问题.
  3. weak_ptr可以被检查为有效:当存在指向对象的shared_ptr时有效.
  4. shared_ptr可以从有效的weak_ptr构造.
  5. 可以从指向对象的有效原始指针构造
  6. weak_ptr.如果存在至少一个弱指针仍指向该对象,则原始指针有效.从无效的指针构造weak_ptr会导致行为未定义.
  7. 像上面提到的现有系统一样,整个智能指针系统应该是易于投射的.
  1. shared_ptr models shared ownership over the object, i.e. the object is destroyed exactly when the last shared_ptr pointing to it is destroyed.
  2. weak_ptr does not model ownership over the object, and it can be used to solve the circular dependency problem.
  3. weak_ptr can be checked for being valid: it is valid when there exists a shared_ptr pointing to the object.
  4. shared_ptr can be constructed from a valid weak_ptr.
  5. weak_ptr can be constructed from a valid raw pointer to the object. Raw pointer is valid if there exists at least one weak_ptr still pointing to that object. Constructing weak_ptr from invalid pointer results in undefined behavior.
  6. The whole smart pointer system should be cast-friendly, like the abovementioned existing systems.

可以进行入侵,即要求用户从给定的基类继承一次.还可以在对象已被销毁时保留其内存.拥有线程安全性非常好(除非效率太低),但是没有它的解决方案也很有趣.可以为每个对象分配几个内存块,但最好每个对象分配一个内存块.

It is OK for being intrusive, i.e. asking the user to inherit once from given base class. Holding the object's memory when the object is already destroyed is also OK. Thread safety is very good to have (unless being too inefficient), but solutions without it are also interesting. It is OK to allocate several chunks of memory per object, though having one memory chunk per object is preferred.

推荐答案

  • 点1-4和点6已由shared_ptr/weak_ptr建模.

    • Points 1-4 and 6 are already modelled by shared_ptr/weak_ptr.

      第5点毫无意义.如果共享生存期,则weak_ptr存在但没有shared_ptr时没有有效的对象.任何原始指针将是无效的指针.对象的生命周期已经结束.该对象不再存在.

      Point 5 makes no sense. If lifetime is shared, then there is no valid object if a weak_ptr exists but a shared_ptr does not. Any raw pointer would be an invalid pointer. The lifetime of the object has ended. The object is no more.

      weak_ptr不会使对象保持活动状态,而是使控制块保持活动状态. shared_ptr使控制块和受控对象都保持活动状态.

      A weak_ptr does not keep the object alive, it keeps the control block alive. A shared_ptr keeps both the control block and the controlled object alive.

      如果您不想通过组合控制块和受控对象来浪费"内存,请不要调用make_shared.

      If you don't want to "waste" memory by combining the control block with the controlled object, don't call make_shared.

      如果您不希望将shared_ptr<X>通过病毒传递给函数,请不要传递它.将引用或const引用传递给X.如果您打算在函数中管理生命周期,则只需在参数列表中提及shared_ptr.如果只想对shared_ptr指向的内容执行操作,请传递*p*p.get()并接受[const]引用.

      If you don't want shared_ptr<X> to be passed virally into functions, don't pass it. Pass a reference or const reference to the X. You only need to mention shared_ptr in the argument list if you intend on managing the lifetime in the function. If you simply want to perform operations on what the shared_ptr is pointing at, pass *p or *p.get() and accept a [const] reference.

      这篇关于与原始指针兼容的(shared_ptr + weak_ptr)设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆