请考虑以下代码:
#include <iostream>
#include <memory>
using namespace std;
class T;
std::weak_ptr<T> wptr;
class T
{
public:
T() { }
~T() {
std::cout << "in dtor" << std::endl;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
};
int main() {
{
auto ptr = std::make_shared<T>();
wptr = ptr;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
return 0;
}
在此代码中,我试图找出对象销毁阶段中weak_ptr
是否已过期。看来是这样。输出是:
not expired
in dtor
expired
我将gcc-5.1与ideone一起使用。
现在,我有另一个问题。我找不到任何文档说明这是标准行为。是否保证以这种方式工作,始终?
答案 0 :(得分:8)
现在,我有另一个问题。我找不到任何文件说明这是标准行为。是否保证以这种方式工作,始终?
没有。实际上,正如LWG issue 2751提出的那样,它在标准中没有明确规定。
C ++ 14标准不包含任何语言,以保证
shared_ptr
运行删除器会将所有关联的weak_ptr
实例视为已过期。例如,标准似乎并不能保证以下代码段中的断言不会被解雇:std::weak_ptr<Foo> weak; std::shared_ptr<Foo> strong{ new Foo, [&weak] (Foo* f) { assert(weak.expired()); delete f; }, }; weak = strong; strong.reset();
似乎很明显,目标是关联的
weak_ptr
已过期,因为否则shared_ptr
删除者可以恢复对正在删除的对象的引用。建议修复:23.11.3.2 [util.smartptr.shared.dest]应指定在调用删除符或调用
use_count()
之前对析构函数引起的delete p
减少进行排序。
上面链接的~shared_ptr()
的当前措辞仅表示调用了删除操作,并且非规范性地说明共享所有权的实例数量减少了。
虽然调用删除器的意图可能是weak.expired()
,但依赖于此是有问题的。确切地说明shared_ptr
在被销毁之后不再共享所有权是非常合理的 - 在期间提出问题破坏有点奇怪。
答案 1 :(得分:5)
像这样使用make_shared将使用您提供的默认构造函数创建一个对象。
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
构造一个T类型的对象并将其包装在
一样构造std::shared_ptr
中 使用args作为T的构造函数的参数列表。该对象 就像表达式(std::make_shared)
在主要的匿名范围之后。共享的ptr将被删除。
当任何一个对象被破坏并且其内存被释放时,该对象被解除 发生以下情况:
拥有该对象的最后剩余的shared_ptr被销毁; (std::shared_ptr)
shared_ptr的析构函数减少了共享所有者的数量 控制块。如果该计数器达到零,则控制块 调用托管对象的析构函数。控制块没有 释放自己直到std :: weak_ptr计数器达到零为止 好。 std::shared_ptr Implementation notes
这意味着您的对象将在最后一个共享ptr的破坏开始后调用其析构函数。 输出:
not expired
in dtor
expired
是预期的行为。
答案 2 :(得分:0)
不是标准本身,但是:
http://en.cppreference.com/w/cpp/memory/weak_ptr/expired
检查托管对象是否已被删除。当量 to use_count()== 0。
因此,在删除之前或之后将天气use_count
设置为0成为问题。现在标准草案中没有这个:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf [第566页20.9.2.2.2]
~shared_ptr()
;效果:
- 如果
*this
为空或与另一个shared_ptr
实例共享所有权(use_count()&gt; 1),则无副作用。- 否则,如果
*this
拥有对象p
和删除者d
,则会调用d(p)
。- 否则,
*this
拥有指针p
,并且会调用delete p
。[注意:由于
*this
的破坏减少了数量 在*this
之后,与*this
共享所有权的实例 已销毁所有共享所有权的shared_ptr
个实例*this
会报告比之前少一个的use_count()
值。 - 结束说明]
答案 3 :(得分:0)
当weak_ptr
没有引用该对象时,shared_ptr
到期。
当最后一个shared_ptr
停止时(紧接其后)引用该对象时,它被摧毁。
此时没有shared_ptr
引用它,因此任何weak_ptr
都已过期。
现在调用了对象的析构函数,如果它有单独的存储(即没有用make_shared
创建),则会释放其存储空间。
如果存在引用它的任何weak_ptr
,则存储引用计数和原始指针以及删除功能的控制块将一直存在。当最后一个weak_ptr
停止引用它时,控制块也会被销毁并解除分配。即,shared_ptr
实例使对象本身及其控制块保持活动状态,而weak_ptr
实例使控制块保持活动状态。