繁体   English   中英

只与一个所有者建立一个shared_ptr

[英]Make a shared_ptr with only one owner

我在C ++ 11中有一个只有一个所有者的对象。 但是,其他对象可以将weak_ptr保存到此对象。 这样,我可以在使用之前测试对象是否仍然存在。

目前,所有者拥有该对象的shared_ptr ,该对象的所有者总数为1。

如何确保不允许任何人制作此shared_ptr的副本?

我不能使用unique_ptr因为显然C ++ 11不允许从unique_ptr创建weak_ptr

编辑 :谢谢你的回复!

所有程序都在一个线程上运行。 主要拥有一个定期更新循环,在其中调用其所有子系统。

感谢您指出使用weak_ptr实际上创建了一个shared_ptr 期望在调用另一个非const函数期间不允许子系统或对象存储shared_ptr 这样,任何函数都可以要求所有者从其集合中删除对象,并立即删除该对象。

我希望每次子系统调用lock()时都要避免增加shared_ptr引用计数的开销,因为它应该立即释放所有权(并确保在编译时就是这种情况)。

编辑2 :更清楚地表达我的问题的示例代码

class Manager {
  public:
    Manager();           //Creates objects and stuff
    void updateAllObjects() {
      for (auto& o : mObjects)
        o->update(*this);
    }
    void deleteObject(weak_ptr<WorldObject>);    //May be called by other objects
    vector<shared_ptr<WorldObject>> mObjects;
};

class WorldObject {
  public:
    virtual void update(Manager&)=0;
};

class Passenger : public WorldObject {
  public:
    void update(Manager&);
};

class Car : public WorldObject {
  public:
    void update(Manager&);    //May call Manager::deleteObject on its passengers, or change them etc...
    //If Manager decides to delete passenger, they must be destroyed, so we don't want those references to count
    vector<weak_ptr<Passenger>> mPassengers;
    //A passenger can belong to several cars, and must be updated exactly once per WorldObject::update()
};

如何: - 避免存储许多shared_ptr的开销 - 确保Car不会将shared_ptr存储给乘客的时间超过其Car::update()函数

目前,所有者拥有该对象的shared_ptr,该对象的所有者总数为1。

这是一个错误的声明,因为std::weak_ptr所有者只能通过创建std::shared_ptr来使用它,所以所有者数量将> 1.所以你的问题几乎毫无意义 - 如果你想只提供独占访问权限对象移动std::unique_ptr ,如果你想通过std::weak_ptr使用它,它必须是共享的,原则上你不能强制执行单个所有者。

你不能, shared_ptr的本质是你可以创建更多的实例。 你可以做的是使它成为类的私有成员,并且不要像现在那样直接将shared_ptr公开给外部世界。 但是你无法安全地使用哑巴,有人可以获得一个weak_ptr ,提取原始指针并删除它。 如果yoru级的用户想要用脚射击自己,那么你无能为力!

如果不实现自己的valid_ptr或类似的东西,就不能这样做,因为你总是可以通过weak_ptr :: lock获得另一个shared_ptr。 也就是说,只有当你想要定期检查对象是否被删除时(即不检查对象是否仍然存在或实际访问它,请参阅下文!)

template<typename T>
class valid_ptr {
public:
     template<typename S>
     valid_ptr(const std::weak_ptr<S>& r) : m_ptr(r) { }
     bool expired() const { return m_ptr.expired(); }
private:
     std::weak_ptr<T> m_ptr;
};

如果你真的想要访问你的指针,那么你应该简单地使用weak_ptr它的意图,并通过weak_ptr::lock获取访问持续时间的shared_ptr:

if (auto shared = weak.lock()) {
    // ptr is valid and can now be used via the shared_ptr shared
} else {
    // ptr is nullptr
}

你不应该只是依靠一个积极的expired检查来访问该对象,因为在检查和访问之间可能发生任何事情(包括被删除的对象,除非你有一些额外的约束,你没有在你的问题中提到)。 在这种情况下,您希望通过在访问期间获取shared_ptr来确保(共享)所有权。

不要这样做。

如果你必须:

将共享ptr用于包含可写的唯一ptr包装的互斥锁定仿函数。

其他人获取共享ptr到一个互斥包装函数包装一个可能为null的不可变原始ptr,通过包装上面的方法并在apply公开.get()结果来实现。

所有者仿函数由一位代码拥有。 它暴露了非所有者的仿函数。 它可以摧毁独特的ptr。

非所有者仿函数不能延长对象的生命周期超过其互斥锁。

所有者仿函数可以将唯一的ptr设置为空,并且(一旦它们具有互斥锁),没有人可以阻止它们。

您可以使用共享互斥锁来允许多个读者。

仿函数是什么意思?

仿函数是包含另一种支持apply的类型的类型。 如果[T]是仿函数类型,并且T是包装类型,并且T->U是取T并返回U的函数的类型,则apply操作的类型为:

([T],(T->U))->U

要么

[T].apply(T->U)

返回一个U

如果T是一个类型,则将T->U应用于T以获得U

如果[T]是一个仿函数T ,那么你将它应用于T->U获得U (注意与前一段相比,措辞略有变化)。

T的函子知道如何运行T函数,但没有声称 T

实施明智,它要么包含一个T要么知道如何在被问到时获得一个。 它可以使它是如何运行的功能的其他担保(例如,具有互斥锁保护,在一个专门的线程,在服务器上,等等)。

有关详细信息,请参阅Haskell。

另请注意,使用合理的公理不能支持重入,因此可以在单个线程上进行死锁。

这个答案不容易理解:我只是为了完整而包含它。 除非你从现代函数编程背景来到C ++,否则任何提出OP问题的人都可能不会得到这个,也不应该尝试(我只是试图表明OP的请求是可能的 ,nkt这是个好主意) 。 更糟糕的是,如果不是设计,我可能会得到一些函数式编程术语错误。

如何将std :: unique_ptr用于对象而不是std :: weak_ptr这是一个指向此std :: unique_ptr的原始指针。 这样,对象只有一个所有者,您可以使用bool运算符通过指向它的原始指针测试std :: unique_ptr的有效性。

auto object = std::make_unique<T>(...); // creates object and std::unique_ptr
...
auto* object_user = &object; // raw pointer to the std::unique_ptr holding the object
...
if ( *object_user ) (*object_user)->... // using the object

注意:省略号是您需要的任何代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM