編集:将来の使用のためにこの質問を読んでいる人へ:エラーは決してunique_ptrとは関係ありませんでした。JoergBが彼の答えで正しく言っているように、基本クラスの仮想デストラクタを忘れるのは私の側の間違いでした。
時折実行時にクラッシュした後、私は自分のコードがメモリリーク炎の深刻なケースに苦しんでいることに気づきました。私はValgrindでプログラムを実行しましたが、医師は同意しているようです。バイトは間違いなく失われます。しかし、私は一生の間、それがどこでうまくいかないのか理解できません。
私は、リークを次の3つの行で発生するように特定することができました。
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
のインスタンスを保持するaが作成されます。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)
Operator
また、呼び出されるまでに演算子が既に構築されているにもかかわらず、Valgrindがコンストラクターでリークが発生することを教えてくれるように見える理由もわかりませんNodeSpace::setNode()
。