2017-11-12 5 views
0

私は、Valgrindによって報告されたように、メモリに誤動作する単純なコードで完全に立ち往生しています。私はこの短いテストケースにそれを減少:再帰構造のベクトルにメモリの問題があります

#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; 
} 

私はそれが二番目のポインタを有する第一その2つの構造を持つ配列を作成することを期待します。実際のソース破壊にセグメンテーション違反でクラッシュしたので、私は、この報告書が重要と考える:あなたは、ベクター中に一backまたはそれ以外の場合は、それを変更したら

==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

が格納されているアイテムへのすべての参照やポインタは、すべてのtailnextフィールドので、無効化されますぶら下がっているポインタが含まれています。逆参照すると、未定義の動作が発生します。実際にはstd::listを使用することもできます(学習の目的で一部のリスト実装を書いているのであれば)、最初にvectorに値を設定してから、それらが有効であることを知っているストアドアイテムへのポインタを収集することができます。

+0

ああ、成長のためのベクトルの再配置が原因ですか? – Ilya

+0

@Ilyaはい、以前のストレージへのポインタが無効になると、ストレージが再配置されました(これは実際に縮小するときにも起こります)。どのメソッドが参照/ポインタ/イテレータを格納されたアイテムに無効にしているかを調べるために、ベクトルメソッドのドキュメントを調べるべきです。 – VTT

関連する問題