std::shared_ptr 为空但不为空
std::shared_ptr which is null but not empty
比较:
std::shared_ptr<T>
别名构造函数让我们玩有趣的游戏。上面的 SO post 讨论了第一个参数是 std::shared_ptr<void>{nullptr}
的情况。我对反过来感兴趣。这是否保证即使 shared_ptr
“是”nullptr
也能使指向的对象保持活动状态(如果我们不保留对它的引用,则将完全无法访问)?:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
ps = nullptr;
assert(ps == nullptr);
assert(p == nullptr);
foo(s); //< Is the S still alive here?
是的,当调用 foo()
时,S
对象仍然存在,因此您的 s
引用仍然有效。
p
的 别名构造函数 将增加 ps
当前持有的 S
对象的引用计数,使该对象保持活动状态,而 p
持有您为其构造函数提供的 nullptr
。当您使用完 p
后,它会减少引用计数。
您可以通过查询引用计数来验证这一点:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
ps = nullptr;
assert(ps == nullptr);
assert(p == nullptr);
cout << ps.use_count() << endl; // prints 0
cout << p.use_count() << endl; // prints 1
foo(s); //< S is still alive here
如果删除 ps = nullptr;
语句,您将看到 ps
和 p
都报告引用计数为 2:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
//ps = nullptr;
assert(ps != nullptr);
assert(p == nullptr);
cout << ps.use_count() << endl; // prints 2
cout << p.use_count() << endl; // prints 2
foo(s); //< S is still alive here
是的,“null 但不为空”shared_ptr
将使对象保持活动状态,因为它与构造它的 shared_ptr
共享所有权。彼此共享所有权的所有 shared_ptr
都会对存储在控制块中的原子引用计数做出贡献,并且只有当此引用计数为零时,拥有的对象才会被销毁。
对于标准语,请参阅 [util.smartptr.shared.const]/14:
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
Constructs a shared_ptr
instance that stores p
and shares ownership with r
p
的值没有指定约束;因此,它可以是任何有效的指针值,包括 null 甚至是尾后指针(尽管我不确定您为什么要这样做)。
然后看[util.smartptr.shared.dest]/(1.1):
If *this
is empty or shares ownership with another shared_ptr
instance (use_count() > 1
), there are no side effects.
也就是说,当ps
被销毁时,它仍然与p
共享所有权,所以对象还没有被销毁。
生成的对象并不是通常意义上的真正不可访问,因为它仍然有可能销毁它。你不能用它做任何其他事情。
比较:
std::shared_ptr<T>
别名构造函数让我们玩有趣的游戏。上面的 SO post 讨论了第一个参数是 std::shared_ptr<void>{nullptr}
的情况。我对反过来感兴趣。这是否保证即使 shared_ptr
“是”nullptr
也能使指向的对象保持活动状态(如果我们不保留对它的引用,则将完全无法访问)?:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
ps = nullptr;
assert(ps == nullptr);
assert(p == nullptr);
foo(s); //< Is the S still alive here?
是的,当调用 foo()
时,S
对象仍然存在,因此您的 s
引用仍然有效。
p
的 别名构造函数 将增加 ps
当前持有的 S
对象的引用计数,使该对象保持活动状态,而 p
持有您为其构造函数提供的 nullptr
。当您使用完 p
后,它会减少引用计数。
您可以通过查询引用计数来验证这一点:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
ps = nullptr;
assert(ps == nullptr);
assert(p == nullptr);
cout << ps.use_count() << endl; // prints 0
cout << p.use_count() << endl; // prints 1
foo(s); //< S is still alive here
如果删除 ps = nullptr;
语句,您将看到 ps
和 p
都报告引用计数为 2:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
//ps = nullptr;
assert(ps != nullptr);
assert(p == nullptr);
cout << ps.use_count() << endl; // prints 2
cout << p.use_count() << endl; // prints 2
foo(s); //< S is still alive here
是的,“null 但不为空”shared_ptr
将使对象保持活动状态,因为它与构造它的 shared_ptr
共享所有权。彼此共享所有权的所有 shared_ptr
都会对存储在控制块中的原子引用计数做出贡献,并且只有当此引用计数为零时,拥有的对象才会被销毁。
对于标准语,请参阅 [util.smartptr.shared.const]/14:
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
Constructs ashared_ptr
instance that storesp
and shares ownership withr
p
的值没有指定约束;因此,它可以是任何有效的指针值,包括 null 甚至是尾后指针(尽管我不确定您为什么要这样做)。
然后看[util.smartptr.shared.dest]/(1.1):
If
*this
is empty or shares ownership with anothershared_ptr
instance (use_count() > 1
), there are no side effects.
也就是说,当ps
被销毁时,它仍然与p
共享所有权,所以对象还没有被销毁。
生成的对象并不是通常意义上的真正不可访问,因为它仍然有可能销毁它。你不能用它做任何其他事情。