使用 std::weak_ptr 和 std::shared_ptr 进行遮蔽
Using std::weak_ptr with std::shared_ptr for shadowing
std::weak_ptr
on cppreference 的文档是这样说的
Effectively returns expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
, executed atomically.
并且我的判断和other SO answers已经确认以下是不容易出现种族问题的
int main() {
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
auto one = std::thread{[&]() {
auto ptr = w_ptr.lock();
if (ptr) { ... }
}};
s_ptr = std::make_shared<T>(...);
one.join();
}
然而,这能否可靠地用于程序中的影子计算?通过阴影我的意思是这样的
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
// thread one
while (...) {
auto ptr = w_ptr.lock();
cout << "Value contained is " << *ptr << endl;
}
// thread two
while (...) {
// do the heavy computation on the side
auto new_value = fetch_new_value();
// then "atomically" swap
s_ptr = std::make_shared<T>(std::move(new_value));
}
这里令人困惑的部分是 .lock()
return。可以return一个nullptr
吗?所有文档都说该操作将以原子方式执行。没有说这个互斥是什么意思。 shared_ptr::operator=
中是否存在指针为空的状态? weak_ptr
可以访问此状态吗? shared_ptr::operator=
on cppreference 的文档似乎没有提到这一点。
一旦您的共享指针获得新值,您的弱指针将开始返回 nullptr
原因是一旦您的共享指针开始指向另一个对象,原始对象就会被销毁。
但是不会有未定义的行为交换指针,因为切换是原子的。
(不过,取消引用 w_ptr.lock()
返回的 nullptr
值共享指针是未定义的,可能会使程序崩溃)。
每次使用新值重置共享指针时,您都需要获取一个新的弱指针。但是当你lock()
你的弱指针时共享指针是否仍然指向那个新值是任何人的猜测。
任何与控制块(引用计数)相关的东西都是原子的。因此,获取新的弱指针是线程安全的,但不能保证指向任何东西(如果其他线程可以访问您的共享指针)。
这段代码可以执行UB:
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
// thread one
while (...) { // A
auto ptr = w_ptr.lock(); // B
cout << "Value contained is " << *ptr << endl; // C
}
// thread two
while (...) {
// do the heavy computation on the side
auto new_value = fetch_new_value();
// then "atomically" swap
s_ptr = std::make_shared<T>(std::move(new_value)); // X
}
如果线程二 // X
在线程一执行 // B
之前执行,weak_ptr
不再引用任何数据。
.lock()
然后 returns a "null" shared_ptr
,您在 // C
.
继续取消引用
如果您使用 ptr
防止它为 null,则不会有明显的 UB。
std::weak_ptr
on cppreference 的文档是这样说的
Effectively returns
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
, executed atomically.
并且我的判断和other SO answers已经确认以下是不容易出现种族问题的
int main() {
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
auto one = std::thread{[&]() {
auto ptr = w_ptr.lock();
if (ptr) { ... }
}};
s_ptr = std::make_shared<T>(...);
one.join();
}
然而,这能否可靠地用于程序中的影子计算?通过阴影我的意思是这样的
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
// thread one
while (...) {
auto ptr = w_ptr.lock();
cout << "Value contained is " << *ptr << endl;
}
// thread two
while (...) {
// do the heavy computation on the side
auto new_value = fetch_new_value();
// then "atomically" swap
s_ptr = std::make_shared<T>(std::move(new_value));
}
这里令人困惑的部分是 .lock()
return。可以return一个nullptr
吗?所有文档都说该操作将以原子方式执行。没有说这个互斥是什么意思。 shared_ptr::operator=
中是否存在指针为空的状态? weak_ptr
可以访问此状态吗? shared_ptr::operator=
on cppreference 的文档似乎没有提到这一点。
一旦您的共享指针获得新值,您的弱指针将开始返回 nullptr
原因是一旦您的共享指针开始指向另一个对象,原始对象就会被销毁。
但是不会有未定义的行为交换指针,因为切换是原子的。
(不过,取消引用 w_ptr.lock()
返回的 nullptr
值共享指针是未定义的,可能会使程序崩溃)。
每次使用新值重置共享指针时,您都需要获取一个新的弱指针。但是当你lock()
你的弱指针时共享指针是否仍然指向那个新值是任何人的猜测。
任何与控制块(引用计数)相关的东西都是原子的。因此,获取新的弱指针是线程安全的,但不能保证指向任何东西(如果其他线程可以访问您的共享指针)。
这段代码可以执行UB:
auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};
// thread one
while (...) { // A
auto ptr = w_ptr.lock(); // B
cout << "Value contained is " << *ptr << endl; // C
}
// thread two
while (...) {
// do the heavy computation on the side
auto new_value = fetch_new_value();
// then "atomically" swap
s_ptr = std::make_shared<T>(std::move(new_value)); // X
}
如果线程二 // X
在线程一执行 // B
之前执行,weak_ptr
不再引用任何数据。
.lock()
然后 returns a "null" shared_ptr
,您在 // C
.
如果您使用 ptr
防止它为 null,则不会有明显的 UB。