下面是一些显示我的用例的示例代码。我有一个 PIMPL,可以在其中共享实现(它只是一堆昂贵的数据),但是当不再需要时,可以销毁实现。该类的一个实例HasImpl使用一个指向 的共享指针Impl,并且该类定义包括一个static weak_ptrto Impl,它充当指向 的新实例的“指针分配器” HasImpl,为它们提供一个句柄,以表明Impl是否已经存在。
该示例有两种调用weak_ptr::lock方式——一种假设下面问题 1-3 的答案都是“是”,另一种则不是。我更喜欢weak_ptr::lock线程安全的唯一原因是可能有多个线程试图获取指向的指针的副本Impl,如果lock是线程安全的,则大多数执行线程不必传递静态变量定义(线程必须检查它是否已经初始化)并且不必竞争获取互斥锁。
/* In HasImpl.h */
class HasImpl {
public:
HasImpl();
private:
class Impl;
static std::weak_ptr<Impl> sharedImplDispenser;
std::shared_ptr<Impl> myPtrToSharedImpl;
}
/* In HasImpl.cpp */
class HasImpl::Impl {
public:
Impl(); //constructor that takes a lot of time to run
//Lots of stuff, expensively produced, accessable to HasImpl through a shared_ptr to Impl
}
/* hypothetical constructor if weak_ptr::lock is thread-safe */
HasImpl::HasImpl() : myPtrToSharedImpl{sharedImplDispenser.lock()}
{
if (!myPtrToSharedImpl) {
static std::mutex mtx;
std::lockguard<std::mutex> lck(mtx);
myPtrToSharedImpl = sharedImplDispenser.lock();
if (!myPtrToSharedImpl) {
const auto new_impl{std::make_shared<Impl()};
sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
myPtrToSharedImpl = new_impl;
}
}
}
/* hypothetical constructor if weak_ptr::lock is not thread-safe */
HasImpl::HasImpl()
{
static std::mutex mtx;
std::lockguard<std::mutex> lck(mtx);
myPtrToSharedImpl = sharedImpl.lock();
if (!myPtrToSharedImpl) {
const auto new_impl{std::make_shared<Impl()};
sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
myPtrToSharedImpl = new_impl;
}
}
- 假设它不是空的并且在遥远的过去某个时候被分配了一个指针,如果一个线程调用而另一个线程可能正在调用
std::weak_ptr,控制块会好吗?weak_ptr::lockweak_ptr::lock weak_ptr::lock在另一个线程可能将 ptr 分配给空的 weak_ptr 时调用是否足够安全?也就是说,该值将返回 nullptr 还是返回新指针?我不在乎 nullptr 是否是虚假的(也就是说,该分配已经发生,但其他线程还不知道)。我只是不想破坏控制块或从调用中获取无效的指针值。weak_ptr::lock在对象的最后一个 shared_ptr 被销毁时调用线程安全吗?- 如果 1 到 3 有问题,
std::atomic<std::weak_ptr<T>>C++20 会解决这个问题吗?