2017-11-12 1 views
0

Valgrind가보고 한 바와 같이 메모리에 오작동하는 간단한 코드 조각이 있습니다. I이 단락 시험의 경우에 감소 :재귀 구조의 벡터에 메모리 문제가 있습니다.

#include <vector> 

struct el 
{ 
    el * next = nullptr; 
}; 

class list 
{ 
public: 
    list(): tail(nullptr) {} 

    void push_back() 
    { 
     el nw; 
     m_list.push_back(nw); 

     if (tail == nullptr) 
      tail = &m_list.back(); 
     else 
     { 
      tail->next = &m_list.back(); 
      tail = tail->next; 
     } 
    } 

private: 
    std::vector<el> m_list; 
    el * tail; 
}; 

int main() 
{ 
    list a; 
    a.push_back(); 
    a.push_back(); 
    return 0; 
} 

는 I는 두 번째 포인터를 가지고있는 제 2 명 구조 배열을 만들 것으로 예상된다. 실제 소스는 파괴에 세그먼트 폴트와 충돌, 그래서 나는 중요한이 보고서가 있다면 : 저장된 항목에 대한 모든 참조와 포인터를 벡터에와 push_back 또는 그렇지 않으면 변경되면 이렇게 모든 tailnext 필드는 것이다 무효화

==1630== Invalid write of size 8 
==1630== at 0x400A37: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400969: main (in /home/ilya/Projects/algos/a.out) 
==1630== Address 0x5a86c80 is 0 bytes inside a block of size 8 free'd 
==1630== at 0x4C2A8DC: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==1630== by 0x4011D5: __gnu_cxx::new_allocator<el>::deallocate(el*, unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400F79: std::_Vector_base<el, std::allocator<el> >::_M_deallocate(el*, unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400DA3: void std::vector<el, std::allocator<el> >::_M_emplace_back_aux<el const&>(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400B42: std::vector<el, std::allocator<el> >::push_back(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4009FF: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400969: main (in /home/ilya/Projects/algos/a.out) 
==1630== Block was alloc'd at 
==1630== at 0x4C29780: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==1630== by 0x4012BB: __gnu_cxx::new_allocator<el>::allocate(unsigned long, void const*) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4010D2: std::_Vector_base<el, std::allocator<el> >::_M_allocate(unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400CC1: void std::vector<el, std::allocator<el> >::_M_emplace_back_aux<el const&>(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400B42: std::vector<el, std::allocator<el> >::push_back(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4009FF: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x40095D: main (in /home/ilya/Projects/algos/a.out) 
==1630== 
==1630== Invalid read of size 8 
==1630== at 0x400A42: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400969: main (in /home/ilya/Projects/algos/a.out) 
==1630== Address 0x5a86c80 is 0 bytes inside a block of size 8 free'd 
==1630== at 0x4C2A8DC: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==1630== by 0x4011D5: __gnu_cxx::new_allocator<el>::deallocate(el*, unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400F79: std::_Vector_base<el, std::allocator<el> >::_M_deallocate(el*, unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400DA3: void std::vector<el, std::allocator<el> >::_M_emplace_back_aux<el const&>(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400B42: std::vector<el, std::allocator<el> >::push_back(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4009FF: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400969: main (in /home/ilya/Projects/algos/a.out) 
==1630== Block was alloc'd at 
==1630== at 0x4C29780: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) 
==1630== by 0x4012BB: __gnu_cxx::new_allocator<el>::allocate(unsigned long, void const*) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4010D2: std::_Vector_base<el, std::allocator<el> >::_M_allocate(unsigned long) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400CC1: void std::vector<el, std::allocator<el> >::_M_emplace_back_aux<el const&>(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x400B42: std::vector<el, std::allocator<el> >::push_back(el const&) (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x4009FF: list::push_back() (in /home/ilya/Projects/algos/a.out) 
==1630== by 0x40095D: main (in /home/ilya/Projects/algos/a.out) 
+0

벡터 요소의 주소를 가져 와서 숨길 수는 없습니다. 다음 벡터 연산이 벡터 요소를 무효화 할 수 있기 때문입니다. 따라서'tail-> next = & m_list.back();'은 no-no입니다. –

+0

3/5 규칙 및 벡터 요소가 메모리에서 안정적이지 않습니다. – Yakk

답변

2

을 매달려있는 포인터가 들어있다. 그리고 그들을 참조 해제하면 정의되지 않은 동작이 발생합니다. std::list을 실제로 사용할 수 있습니다 (학습 목적으로 일부 목록 구현을 작성하는 경우). 먼저 벡터를 채운 다음 유효한 항목임을 알면 저장된 항목에 대한 포인터를 수집 할 수 있습니다.

+0

오 성장은 벡터 재배치로 인한 것입니까? – Ilya

+0

@Ilya 예, 이전 스토리지로의 포인터가 유효하지 않게되면 스토리지가 재배치되었습니다 (실제로 축소되었을 때 실제로 발생할 수 있음). 벡터 메소드에 대한 문서를 점검하여 어떤 메소드가 저장된 항목에 대한 참조/포인터/반복자를 무효화하는지 알아 내야한다. – VTT

관련 문제