重新创建基于shared_ptr的单例
Re-creating a shared_ptr-based singleton
有一个static shared_ptr<MyClass> get()
,它内部有一个使用ptr.lock()
提供共享指针的weak_ptr
。
当ptr.lock()
给出一个空指针时,应该再次创建单例。
但是它能保证(不能保证)前一个单例的析构函数已经完成吗?对此该怎么办?
但是它能保证(不能保证)前一个单例的析构函数已经完成吗?对此该怎么办?
这是一个不寻常的请求,但我可以看到,如果您正在控制一个外部单例资源,那么它可能是多么必要。
这是我的解决方案。
在生产中使用之前,请确保对其进行彻底检查
#include <memory>
#include <mutex>
#include <condition_variable>
struct tricky_object
{
};
class tricky_cache
{
struct statics {
std::mutex _m;
std::condition_variable _deleted;
bool _exists = false;
std::weak_ptr<tricky_object> _cache;
};
static statics& get() {
static statics _;
return _;
}
public:
static
std::shared_ptr<tricky_object> acquire()
{
// get static data
auto& data = get();
// lock the cache's mutex
auto lock = std::unique_lock<std::mutex>(data._m);
std::shared_ptr<tricky_object> candidate;
// wait on the condition variable for the following conditions to be true:
data._deleted.wait(lock, [&data, &candidate] {
// either the object is in play and we have acquired another reference...
candidate = data._cache.lock();
if (candidate)
return true;
// ... or (if not) the previous object is actually dead and buried.
return !data._exists;
});
// at this point we still own the lock and wait must have returned true, so...
// if we own the candidate then it was already in play
if (candidate)
return candidate;
// otherwise the previous object is certainly destroyed and we may create another
data._cache = candidate = std::shared_ptr<tricky_object>(new tricky_object(),
[&data](tricky_object*p) {
// but the custom deleter needs some trickery
delete p;
if (p) {
auto lock = std::unique_lock<std::mutex>(data._m);
data._exists = false;
lock.unlock();
data._deleted.notify_all();
}
});
// and we should record the fact that the object now exists...
data._exists = true;
lock.unlock();
// ... and inform all waiters that they may continue acquiring
data._deleted.notify_all();
return candidate;
}
};
int main()
{
auto p = tricky_cache::acquire();
return 0;
}
对此可以做些什么?停止使用糟糕的编程风格。
如果要使用singleton,那么它应该是singleton:一个实例,句点。没有必要用智能指针来管理它的生命周期;它总是在那里。破坏它,然后再创造它,这有什么意义?特别是如果娱乐功能没有被赋予特殊的参数,以便以后重新创建它?
然而,对于您的问题:
它能保证(不能保证)前一个单例的析构函数已经完成吗
这有关系吗?为了启动对象的析构函数,对象的shared_ptr
引用计数必须为零。所以weak_ptr
已经是空的。对象的生存期在其析构函数启动时结束(就像对象的生存期限在其构造函数完成时开始一样)。所以单例本身已经被破坏了;你只是在做清理工作。
因此,在旧实例的析构函数的调用堆栈中创建singleton的新实例没有问题。它根本不会访问自己。
线程
在多线程环境中,如果返回/创建singleton的get
函数中没有某种锁,这种接口已经严重损坏。如果没有这种互斥,多个线程可以尝试同时创建singleton,这可能会导致构造多个singleton实例。
至于单体内部的资源,这些资源的释放已经受到某种形式的互斥机制的控制。当资源本身是单例时的唯一时间。但与我们所讨论的单例不同,它将是一个不能由多段代码拥有的单例。
在这种情况下,您的singleton根本不应该拥有该资源的所有权。它可以引用它,但不能销毁或创建它。
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 无法使用 libtool 将 -shared 参数传递给 g++
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- shared-ptr-C++shared_ptr与unique_ptr用于资源管理