I am having a very strange problem with shared_ptr where two Node are using shared_ptr to point to each other.
I paste my test code and output valgrind first, then follow my understanding.
test code
#include <iostream>
#include <memory>
struct Node {
int val_;
std::shared_ptr<Node> next_;
std::shared_ptr<Node> prev_;
Node(int val)
: val_(val), next_(nullptr), prev_(nullptr) {
}
};
class List {
public:
List()
: head_(nullptr){
}
void insert(int val) {
auto new_node = std::make_shared<Node>(val);
if (!head_)
head_ = new_node;
else {
head_->next_ = new_node;
new_node->prev_ = head_;
}
}
void debug() {
std::shared_ptr<Node> cur;
for (cur = head_; cur != nullptr; cur = cur->next_)
std::cout << cur->val_ << std::endl;
}
private:
std::shared_ptr<Node> head_;
};
int main(int argc, const char *argv[]) {
List l;
l.insert(199);
l.insert(200);
l.debug();
return 0;
}
the output of valgrind.
==8282== Memcheck, a memory error detector
==8282== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8282== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==8282== Command: ./a.out
==8282==
==8282==
==8282== HEAP SUMMARY:
==8282== in use at exit: 128 bytes in 2 blocks
==8282== total heap usage: 2 allocs, 0 frees, 128 bytes allocated
==8282==
==8282== 128 (64 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==8282== at 0x4C28C90: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8282== by 0x401825: __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<Node, std::allocator<Node>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x401751: std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<Node, std::allocator<Node>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<Node, std::allocator<Node>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x4015B1: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<Node, std::allocator<Node>, int&>(std::_Sp_make_shared_tag, Node*, std::allocator<Node> const&, int&) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x4014FB: std::__shared_ptr<Node, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<Node>, int&>(std::_Sp_make_shared_tag, std::allocator<Node> const&, int&) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x401451: std::shared_ptr<Node>::shared_ptr<std::allocator<Node>, int&>(std::_Sp_make_shared_tag, std::allocator<Node> const&, int&) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x40139D: std::shared_ptr<Node> std::allocate_shared<Node, std::allocator<Node>, int&>(std::allocator<Node> const&, int&) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x4011D2: _ZSt11make_sharedI4NodeIRiEESt10shared_ptrIT_EDpOT0_ (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x401000: List::insert(int) (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282== by 0x400DAC: main (in /home/lightmanhk/Backup/repo/scripts_code/docs/c++/tech/module/shared_ptr/a.out)
==8282==
==8282== LEAK SUMMARY:
==8282== definitely lost: 64 bytes in 1 blocks
==8282== indirectly lost: 64 bytes in 1 blocks
==8282== possibly lost: 0 bytes in 0 blocks
==8282== still reachable: 0 bytes in 0 blocks
==8282== suppressed: 0 bytes in 0 blocks
==8282==
==8282== For counts of detected and suppressed errors, rerun with: -v
==8282== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)
understanding
|------| |-------|
|next----------------->|next(nullptr)
|prev(nullptr)|<--------prev |
|------| |-------|
head_ new_node
I believe the reason why I am having the memory leaks is that when List
's destructor gets called, it only reduce the reference to head_
by 1 rather than free the head_
(because new_node->prev_
points to head_
as well). (maybe I am wrong?)
1> my question how to solve this problem.
Hope someone give me suggestions. thanks a lot.