std::bad_alloc 插入到 std::unordered_map 时?
std::bad_alloc when inserting into std::unordered_map?
我有时会收到以下代码的 std::bad_alloc:
typedef std::unordered_map<chash, block_extended_info> map_type;
map_type m_foo;
// the transgressor:
auto r = m_foo.insert(map_type::value_type(id, bei));
它有时会发生,而 运行 测试用例使用包含该行的方法,有时则不会。我已经将代码更改为使用 m_foo[id] = bei
,这导致它在一次编译中停止发生,但是当我再次重新编译时它失败了,所以我将其更改为上面的代码,它继续失败。显然问题比这更深。
我相当确定这不是 运行 内存不足的问题,因为我有 top
运行 而测试用例是 运行 但它没有快填满内存。
什么可能导致 std::bad_alloc? chash
和 block_extended_info
的详细信息可能是什么原因造成的?这些类型的对象在代码的其他部分到处复制和传递,不会导致任何问题。
这里是chash
的定义:
class chash {
char data[32];
};
下面是定义 block_extended_info
所需的一切:
class csignature {
chash c, r;
};
enum foob { /* ... */ };
class ct {
uint64_t a, b;
foob c;
};
typedef boost::variant< /* structs with ints, maps, vectors of ints */ > txin_v;
typedef boost::variant< /* similar structs */ > txout_target_v;
struct tx_out {
uint64_t a;
txout_target_v b;
};
class transaction_prefix
{
public:
size_t version;
uint64_t unlock_time;
std::vector<uint8_t> extra;
protected:
std::vector<txin_v> a;
std::vector<tx_out> b;
std::vector<ct> c;
std::vector<ct> d;
};
class transaction: public transaction_prefix
{
public:
std::vector<std::vector<csignature> > signatures;
};
struct block_header
{
uint8_t major_version;
uint8_t minor_version;
uint64_t timestamp;
chash prev_id;
uint32_t nonce;
};
struct block: public block_header
{
transaction miner_tx;
std::vector<chash> tx_hashes;
uint16_t food_id;
csignature food_sig;
};
struct block_extended_info
{
block bl;
uint64_t height;
size_t block_cumulative_size;
uint64_t cumulative_difficulty;
uint64_t already_generated_coins;
};
绕过 gdb 中的相关区域,这是导致 bad_alloc:
的最新几行
cryptonote::transaction::transaction(cryptonote::transaction const&) () at /usr/include/c++/4.8/bits/stl_vector.h:313
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
117 __uninit_copy(__first, __last, __result);
cryptonote::tx_out* std::__uninitialized_copy<false>::__uninit_copy<__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*>(__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, __gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*) ()
at /usr/include/c++/4.8/bits/stl_uninitialized.h:68
68 __uninit_copy(_InputIterator __first, _InputIterator __last,
74 for (; __first != __last; ++__first, ++__cur)
83 }
cryptonote::transaction::transaction(cryptonote::transaction const&) () at /usr/include/c++/4.8/bits/stl_vector.h:313
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
104 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
71 _ForwardIterator __cur = __result;
75 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
748 ++_M_current;
74 for (; __first != __last; ++__first, ++__cur)
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
570 class transaction: public transaction_prefix
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
104 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
181 this->_M_impl._M_start = this->_M_allocate(__n);
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
101 if (__n > this->max_size())
75 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
102 std::__throw_bad_alloc();
正如 πìντα ῥεῖ 所怀疑的那样,问题出在其他地方。
我列出的代码在一个名为 add_block_as_invalid(...)
的函数中。呼叫站点看起来像这样:
// parameter, iterators into m_alternative_chains
std::list<blocks_ext_by_hash::iterator>& alt_chain;
for(auto alt_ch_iter = alt_chain.begin();
alt_ch_iter != alt_chain.end();
alt_ch_iter++)
{
// ....
auto ch_ent = *alt_ch_iter;
// ....
m_alternative_chains.erase(ch_ent);
for(auto alt_ch_to_orph_iter = ++alt_ch_iter;
alt_ch_to_orph_iter != alt_chain.end();
alt_ch_to_orph_iter++)
{
add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first);
m_alternative_chains.erase(*alt_ch_to_orph_iter);
}
}
对 add_block_as_invalid
的调用一直取消引用 alt_ch_iter
,它已被删除。
我有时会收到以下代码的 std::bad_alloc:
typedef std::unordered_map<chash, block_extended_info> map_type;
map_type m_foo;
// the transgressor:
auto r = m_foo.insert(map_type::value_type(id, bei));
它有时会发生,而 运行 测试用例使用包含该行的方法,有时则不会。我已经将代码更改为使用 m_foo[id] = bei
,这导致它在一次编译中停止发生,但是当我再次重新编译时它失败了,所以我将其更改为上面的代码,它继续失败。显然问题比这更深。
我相当确定这不是 运行 内存不足的问题,因为我有 top
运行 而测试用例是 运行 但它没有快填满内存。
什么可能导致 std::bad_alloc? chash
和 block_extended_info
的详细信息可能是什么原因造成的?这些类型的对象在代码的其他部分到处复制和传递,不会导致任何问题。
这里是chash
的定义:
class chash {
char data[32];
};
下面是定义 block_extended_info
所需的一切:
class csignature {
chash c, r;
};
enum foob { /* ... */ };
class ct {
uint64_t a, b;
foob c;
};
typedef boost::variant< /* structs with ints, maps, vectors of ints */ > txin_v;
typedef boost::variant< /* similar structs */ > txout_target_v;
struct tx_out {
uint64_t a;
txout_target_v b;
};
class transaction_prefix
{
public:
size_t version;
uint64_t unlock_time;
std::vector<uint8_t> extra;
protected:
std::vector<txin_v> a;
std::vector<tx_out> b;
std::vector<ct> c;
std::vector<ct> d;
};
class transaction: public transaction_prefix
{
public:
std::vector<std::vector<csignature> > signatures;
};
struct block_header
{
uint8_t major_version;
uint8_t minor_version;
uint64_t timestamp;
chash prev_id;
uint32_t nonce;
};
struct block: public block_header
{
transaction miner_tx;
std::vector<chash> tx_hashes;
uint16_t food_id;
csignature food_sig;
};
struct block_extended_info
{
block bl;
uint64_t height;
size_t block_cumulative_size;
uint64_t cumulative_difficulty;
uint64_t already_generated_coins;
};
绕过 gdb 中的相关区域,这是导致 bad_alloc:
的最新几行cryptonote::transaction::transaction(cryptonote::transaction const&) () at /usr/include/c++/4.8/bits/stl_vector.h:313
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
117 __uninit_copy(__first, __last, __result);
cryptonote::tx_out* std::__uninitialized_copy<false>::__uninit_copy<__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*>(__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, __gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*) ()
at /usr/include/c++/4.8/bits/stl_uninitialized.h:68
68 __uninit_copy(_InputIterator __first, _InputIterator __last,
74 for (; __first != __last; ++__first, ++__cur)
83 }
cryptonote::transaction::transaction(cryptonote::transaction const&) () at /usr/include/c++/4.8/bits/stl_vector.h:313
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
104 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
71 _ForwardIterator __cur = __result;
75 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
748 ++_M_current;
74 for (; __first != __last; ++__first, ++__cur)
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
570 class transaction: public transaction_prefix
313 { this->_M_impl._M_finish =
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
104 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
181 this->_M_impl._M_start = this->_M_allocate(__n);
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
181 this->_M_impl._M_start = this->_M_allocate(__n);
182 this->_M_impl._M_finish = this->_M_impl._M_start;
183 this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
310 vector(const vector& __x)
74 for (; __first != __last; ++__first, ++__cur)
101 if (__n > this->max_size())
75 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
646 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
91 : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
168 { return __n != 0 ? _M_impl.allocate(__n) : 0; }
101 if (__n > this->max_size())
102 std::__throw_bad_alloc();
正如 πìντα ῥεῖ 所怀疑的那样,问题出在其他地方。
我列出的代码在一个名为 add_block_as_invalid(...)
的函数中。呼叫站点看起来像这样:
// parameter, iterators into m_alternative_chains
std::list<blocks_ext_by_hash::iterator>& alt_chain;
for(auto alt_ch_iter = alt_chain.begin();
alt_ch_iter != alt_chain.end();
alt_ch_iter++)
{
// ....
auto ch_ent = *alt_ch_iter;
// ....
m_alternative_chains.erase(ch_ent);
for(auto alt_ch_to_orph_iter = ++alt_ch_iter;
alt_ch_to_orph_iter != alt_chain.end();
alt_ch_to_orph_iter++)
{
add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first);
m_alternative_chains.erase(*alt_ch_to_orph_iter);
}
}
对 add_block_as_invalid
的调用一直取消引用 alt_ch_iter
,它已被删除。