编辑:对于阅读此问题以供将来使用的任何人:错误无论如何都与unique_ptr无关。简单地说,正如JoergB在他的回答中所说的那样,我错误地忘记了基类的虚拟析构函数。
偶尔运行时崩溃后,我发现我的代码遭遇了严重的内存泄漏问题。我用Valgrind运行我的程序,医生似乎同意:字节肯定丢失。但是我不能为我的生活找出它出错的地方。
我设法将泄漏事件发生在这三行中:
std::unique_ptr<Operator> pointer(new Operator{"left", "right"});
NodeSpace space; // The node space takes ownership over the operator
// When I comment out the following line, Valgrind reports nothing:
space.setNode("key", move(pointer));
在第一行中创建了unique_pointer
,其中包含Operator
类的实例。 Operator
内部看起来像这样:
class Operator : public Node {
public:
Operator(std::initializer_list<std::string> input_keys) {
input_nodes_.reserve(input_keys.size());
for_each(begin(input_keys), end(input_keys), [this](const string& key) {
input_nodes_[key] = nullptr;
});
}
// ...
private:
std::unordered_map<std::string, Node*> input_nodes_;
};
我将unique_ptr
r值引用传递给以下函数:
void NodeSpace::setNode(const std::string& key, std::unique_ptr<Node> node);
因为节点空间接管了传入节点的所有权,所以它需要unique_ptr
个值(移动语义)。在内部它将指针存储在std::map
中,但即使函数体被注释掉,内存泄漏仍然会发生(这使我相信问题是函数调用的node
参数)。
任何人都可以远程了解问题所在?
旁注:我没有使用shared_ptr
,因为节点可以循环方式相互引用。 weak_ptr
可以是一个选项,但是通过构建系统,当一个节点不再拥有它所拥有的节点空间时,它就不可能存在。
Valgrind输出:
==83791== 112 (16 direct, 96 indirect) bytes in 1 blocks are definitely lost in loss record 606 of 794
==83791== at 0x100060ABD: malloc (vg_replace_malloc.c:274)
==83791== by 0x1000C9147: operator new(unsigned long) (in /usr/lib/libc++.1.dylib)
==83791== by 0x10000CB0F: std::__1::__hash_table<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*>, std::__1::__unordered_map_hasher<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::__unordered_map_equal<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*> > >::__rehash(unsigned long) (in ./test/mimi)
==83791== by 0x10000C684: std::__1::__hash_table<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*>, std::__1::__unordered_map_hasher<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::__unordered_map_equal<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, true>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, mimi::Node*> > >::rehash(unsigned long) (in ./test/mimi)
==83791== by 0x100005D5A: mimi::Operator::Operator(std::initializer_list<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >) (in ./test/mimi)
==83791== by 0x100005984: mimi::Operator::Operator(std::initializer_list<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >) (in ./test/mimi)
==83791== by 0x10002E940: main (in ./test/mimi)
我也不明白为什么Valgrind似乎告诉我Operator
构造函数中发生了泄漏,即使在调用NodeSpace::setNode()
时已经构造了运算符。
答案 0 :(得分:5)
您没有向我们展示代码的关键部分 - Node
的声明,特别是其析构函数,NodeSpace
的部分,特别是它如何删除Node
s等等。但是从您的评论&#34; Node和Operator都没有任何析构函数和复制/移动构造函数/赋值运算符&#34;,似乎这就是问题所在。
如果您通过Operator
或Node *
保留unique_ptr<Node>
的所有权,即通过Node *
删除任何衍生对象,Node
< strong>必须拥有虚拟析构函数。如果你没有声明并定义一个,那就没有了。
虽然结果行为未定义,但结果通常是,不调用派生类成员的析构函数。这符合您的错误消息。