在下面的代码中,我希望断言能够通过,但事实并非如此。
这与documented behavior of unique_ptr::reset不同,我觉得这很令人惊讶。
我做错了什么或是错误吗?这是一个问题,因为如果删除相同的元素增益,则会调用析构函数两次。
#include <set>
#include <memory>
struct F
: std::enable_shared_from_this<F>
{
static int destructor_count;
static std::set<std::shared_ptr<F>> container;
F() {}
~F() {
assert(container.size() == 0);
container.clear(); // This will delete the same pointer twice.
destructor_count--;
}
};
int F::destructor_count = 0;
std::set<std::shared_ptr<F>> F::container;
int main()
{
F::container.insert(std::shared_ptr<F>(new F));
F::container.clear();
return 0;
}
编译器信息:
的libstdc ++ 6-4.6-dev的
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
答案 0 :(得分:2)
有一个原因unique_ptr
被明确记录为以这种方式行事:它比通常用于标准库的其他部分的保证更强。如果同一规则适用于所有类型,则无需专门针对unique_ptr
声明。
您的代码递归调用F::container.clear()
,而另一个F::container.clear()
调用正在运行。这不能保证有效:
17.6.5.8可重入[reentrancy]
除非在本标准中明确指定,否则它是实现定义的,可以递归地重新输入标准C ++库中的函数。
现在不幸的是libstdc ++无法记录哪些函数可以递归重新输入,所以假设没有一个函数可以更安全,所以你的断言是不正确的。
答案 1 :(得分:1)
在清空容器时调用F的析构函数,在此期间容器不为空,因此断言失败。
答案 2 :(得分:1)
我不确定为什么你会认为断言是真的。您不应该知道容器如何容纳和破坏内存的细节。你不应该对std::set::clear()
期间发生的事情做出假设,只相信在完成所有析构函数之后,std::set::size()
将返回0。
在这篇旧Dobbs博士文章STL's Red-Black Trees中,描述了std::set
背后的支持数据结构。在整个树为空之前,节点将被删除(并且它们的内容被破坏),但是在std::set::clear()
结束时将保证将调用所有析构函数并且std::set::size()
将返回0。
注意:std::set
的其他实现可能使用不同的后备数据结构,红黑树只是一种可能的实现。