mac osx 10.3.9
gcc/g++ は 3.3です.
あるc++プログラムをコンパイルしてgdbでdebugすると以下のmessageが出ます.
vectorが悪さをしていると思うのですが, 対処法が分かりません.
アドバイスよろしくお願いします.
Program received signal EXC_BAD_ACCESS, Could not access memory.
0x05c79fdc in std::__default_alloc_template<true, 0>::allocate(unsigned long) () at /usr/include/gcc/darwin/3.3/c++/bits/stl_vector.h:525
525 operator[](size_type __n) const { return *(begin() + __n); }
(gdb) where
#0 0x05c79fdc in std::__default_alloc_template<true, 0>::allocate(unsigned long) () at /usr/include/gcc/darwin/3.3/c++/bits/stl_vector.h:525
以下長過ぎるので, 後ほどのせます.
# 具体的なコード例がないので推測で書きますが…
前回のご質問の補足として私の日記に書きましたが、GCC 3.3 系列の std::allocator にはバグがあるのではないかと思われます。
どうしても 3.3 系列を使う必要があるのでなければ、3.4 系列以降を使った方が良いと思います。
どうしても 3.3 系列を使う必要があるのなら、独自のアロケーターを指定するか、std::allocator を修正してみてはいかがでしょうか。
ありがとうございます. やはりそうですか.
実際, gcc/g++を3.4.6に上げると, 上のようなmessageは出ません.
実は, 元々は, ある数値計算用softwareからc++を呼び出していて, そのsoftwareでは, この環境ならgcc/g++は3.3で大丈夫だと言っていて, やっぱり自分のc++に問題があるのかなと悩んでいました. が, これではっきりとgcc/g++の方に問題があるという自信が持てました.
gcc/g++の方に問題がある
当方の環境では、gdb でご質問のようなエラーを再現できませんでしたので断言はできませんが、ご質問の環境で次のような単純なアロケーターを指定して、ご質問のようなエラーにならなければ、より可能性が高くなると思います。
(当方の環境では、これで valgrind でメモリーリークは検出されなくなりました。)
当方の環境:
アロケーターの例:
my_allocator.hpp
#ifndef MY_ALLOCATOR_HPP #define MY_ALLOCATOR_HPP #include <cstddef> #include <limits> template<typename T> class my_allocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T *pointer; typedef const T *const_pointer; typedef T &reference; typedef const T &const_reference; typedef T value_type; template<typename U> struct rebind { typedef my_allocator<U> other; }; my_allocator() throw() {} my_allocator(const my_allocator &) throw() {} template<typename U> my_allocator(const my_allocator<U> &) throw() {} ~my_allocator() throw() {} pointer address(reference value) const { return &value; } const_pointer address(const_reference value) const { return &value; } size_type max_size() const throw() { return std::numeric_limits<std::size_t>::max() / sizeof(T); } pointer allocate(size_type num, const void * = 0) { return static_cast<pointer>(::operator new(num * sizeof(T))); } void construct(pointer p, const T &value) { ::new(p) T(value); } void destroy(pointer p) { p->~T(); } void deallocate(pointer p, size_type) { ::operator delete(p); } }; template<typename T1, typename T2> bool operator==(const my_allocator<T1> &, const my_allocator<T2> &) throw() { return true; } template<typename T1, typename T2> bool operator!=(const my_allocator<T1> &, const my_allocator<T2> &) throw() { return false; } #endif // !MY_ALLOCATOR_HPP
使用例:
#include <vector> #include "my_allocator.hpp" #include <iostream> #define DEFAULT_ALLOCATOR my_allocator //#define DEFAULT_ALLOCATOR std::allocator typedef std::vector<int, DEFAULT_ALLOCATOR<int> > vec_int; typedef std::vector<vec_int, DEFAULT_ALLOCATOR<vec_int> > vec_vec_int; int main() { vec_vec_int obj; for ( vec_vec_int::size_type i = 0; i < 128; ++i ) { obj.push_back(vec_int()); for ( vec_int::size_type j = 0; j < 256; ++j ) { obj[i].push_back(j); } } for ( vec_vec_int::size_type i = 0; i < obj.size(); ++i ) { std::cout << "---- " << i << "\n"; for ( vec_int::size_type j = 0; j < obj[i].size(); ++j ) { std::cout << obj[i][j] << ","; } std::cout << std::endl; } }
そのsoftwareでは, この環境ならgcc/g++は3.3で大丈夫だと言っていて
バージョンを変えられそうもない状況のようですね。
となると、次のような対策が考えられますが、(2)が比較的簡単かつ影響が少ないのではないかと思います。
(std::allocator がバグっているという前提)
(1)std::allocator を修正する
(2)独自のアロケーターを指定する
(3)std::allocator を、独自のコード(アロケーター)に置き換える
(4)STL を STLport 等に替える
返信ありがとうございます
実は, このプログラムは, この環境でmemory leakを起こしていて, それが原因で, 回答のようになっているかもしれません.
Vine Linux 4.0
gcc/g++ 3.4.4
だと, valgrind 3.2.3ではmemory leakもなく, gdbでこのようなmessageは出ません.
なお, 以下に gdb のlog を...
<---ココから
#1 0x05cb978c in std::vector<int, std::allocator<int> >* std::__uninitialized_copy_aux<__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > const*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, std::vector<int, std::allocator<int> >*>(__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > const*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, __gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > const*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, std::vector<int, std::allocator<int> >*, __false_type) (__first={<iterator<std::random_access_iterator_tag,std::vector<int, std::allocator<int> >,int,const std::vector<int, std::allocator<int> >*,const std::vector<int, std::allocator<int> >&>> = {<No data fields>}, _M_current = 0x5cd903c}, __last={<iterator<std::random_access_iterator_tag,std::vector<int, std::allocator<int> >,int,const std::vector<int, std::allocator<int> >*,const std::vector<int, std::allocator<int> >&>> = {<No data fields>}, _M_current = 0x45f9eb0}, __result=0x36e94a8) at /usr/include/gcc/darwin/3.3/c++/bits/stl_alloc.h:232
ココマデ -->