我在C ++ 11中有一个只有一个所有者的对象。但是,其他对象可以为此对象保留weak_ptr
。这样,我可以在使用之前测试对象是否仍然存在。
目前,所有者对该对象有一个shared_ptr
,其所有者的总数为1。
如何确保不允许任何人复制此shared_ptr
?
我无法使用unique_ptr
,因为显然C ++ 11不允许从weak_ptr
中生成unique_ptr
。
编辑:感谢您的回复!
所有程序都在一个线程上运行。主要拥有一个定期更新循环,在其中调用所有子系统。
感谢您指出使用weak_ptr
实际上会创建shared_ptr
。期望在调用另一个非const函数期间不允许子系统或对象存储shared_ptr
。这样,任何函数都可以要求所有者从其集合中删除对象,并立即删除该对象。
我希望避免每次子系统调用shared_ptr
时增加lock()
的引用计数的开销,因为预计会立即释放所有权(并确保在编译时间。)
编辑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()
功能
答案 0 :(得分:5)
现在,所有者拥有一个对象的shared_ptr,它总是有一个 所有者数为1。
这是一个虚假陈述,因为std::weak_ptr
的所有者只能通过创建std::shared_ptr
来使用它,因此所有者的数量将是&gt; 1.所以你的问题几乎毫无意义 - 如果你想只提供对象移动std::unique_ptr
的独占访问权限,如果你想通过std::weak_ptr
使用它,那么它必须是共享的,你不能强制执行老板原则上。
答案 1 :(得分:2)
你不能,shared_ptr
的本质是你可以创建更多的实例。
你可以做的是让它成为班级的私人成员,而不是像现在这样直接将shared_ptr
暴露给外部世界。
但是,你不能安全地对付使用的哑巴,有人也可以获得weak_ptr
,提取原始指针并删除它。如果yoru级别的用户想要用脚射击自己,那么你无能为力!
答案 2 :(得分:1)
如果不实施自己的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来确保(共享)所有权。
答案 3 :(得分:0)
不要这样做。
如果你必须:
将共享ptr用于包含可写独特ptr包装的互斥锁定仿函数。
其他人获取共享ptr到包含可能为null的不可变原始ptr的互斥包装函数,通过包装上述内容并在.get()
中公开apply
结果来实现。
所有者仿函数由一位代码拥有。它暴露了非所有者的仿函数。它可以破坏独特的ptr。
非所有者仿函数无法将对象的生命周期延长到其互斥锁之后。
所有者仿函数可以将唯一的ptr设置为空,并且(一旦它们具有互斥锁),没有人可以阻止它们。
您可以使用共享互斥锁来允许多个读者。
仿函数是什么意思?
仿函数是包含另一种支持apply的类型的类型。如果[T]
是函子类型,并且T
类型已换行,并且T->U
是执行T
并返回U
的函数的类型,则适用操作类型为:
([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这是一个好主意)。更糟糕的是,如果不是设计,我可能会得到一些函数式编程术语错误。
答案 4 :(得分:0)
如何使用 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
注意:省略号是您需要的任何代码。