在 std::map 中搜索时堆栈溢出
Posted
技术标签:
【中文标题】在 std::map 中搜索时堆栈溢出【英文标题】:stack overflow when searching in std::map 【发布时间】:2014-04-13 14:11:48 【问题描述】:这段代码在运行时由于某种原因导致堆栈溢出异常:
neuralnetwork::CPerceptron::inputEvent(const neuralnetwork::IConnection * origin, double value)
std::map<std::reference_wrapper<const IConnection>, float64_t, _CPerceptronComparator>::iterator it = m_inputValues.find( std::ref( *origin ) );
if ( it == m_inputValues.end() )
throw "Some error";
...
_CPerceptronComparator 看起来像这样(它是必需的,因为 std::ref 没有运算符
class _CPerceptronComparator
public:
_CPerceptronComparator()
bool operator()( const std::reference_wrapper<const neuralnetwork::IConnection *> & val1,
const std::reference_wrapper<const neuralnetwork::IConnection *> & val2 ) const
return (val1.get()) < (val2.get());
bool operator()( const std::reference_wrapper<const neuralnetwork::IConnection> & val1,
const std::reference_wrapper<const neuralnetwork::IConnection> & val2 ) const
return &( val1.get() ) < &( val2.get() );
bool operator()( const std::reference_wrapper<neuralnetwork::IConnection> & val1,
const std::reference_wrapper<neuralnetwork::IConnection> & val2 ) const
return &( val1.get() ) < &( val2.get() );
;
我添加了更多代码,因此也许您可以提供帮助。这就是我添加输入连接的方式:
void CPerceptron::addInputConnection( IConnection * inConn )
m_outConnections.insert( std::ref(*inConn) );
m_inputValues.insert( std::pair<std::reference_wrapper<IConnection>, float64_t>( std::ref( *inConn ), 0.0f ) );
m_isInputReady.insert( std::pair<std::reference_wrapper<IConnection>, bool>( std::ref( *inConn ), false ) );
注意:我知道 std::make_pair 更容易使用,但我更换了它,希望它会导致我的问题。你知道,它不可能看穿它返回的那种类型。此解决方案可能更难阅读,但很简单。
错误:Neural Network.exe 中 0x002C2EC9 处的未处理异常:0xC00000FD:堆栈溢出(参数:0x00000001、0x00102FFC)。
调用栈:
Neural Network.exe!std::_Iterator_base12::_Orphan_me() Line 192 C++
Neural Network.exe!std::_Iterator_base12::_Adopt(const std::_Container_base12 * _Parent) Line 165 C++
Neural Network.exe!std::_Iterator_base12::operator=(const std::_Iterator_base12 & _Right) Line 129 C++
Neural Network.exe!std::_Iterator_base12::_Iterator_base12(const std::_Iterator_base12 & _Right) Line 121 C++
Neural Network.exe!std::_Iterator012<std::bidirectional_iterator_tag,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double>,int,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const *,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const &,std::_Iterator_base12>::_Iterator012<std::bidirectional_iterator_tag,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double>,int,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const *,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const &,std::_Iterator_base12>(const std::_Iterator012<std::bidirectional_iterator_tag,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double>,int,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const *,std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> const &,std::_Iterator_base12> & __that) C++
Neural Network.exe!std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > >,std::_Iterator_base12>::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > >,std::_Iterator_base12>(const std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > >,std::_Iterator_base12> & __that) C++
Neural Network.exe!std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > >::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > >(const std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > > & __that) C++
Neural Network.exe!std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > >::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > >(const std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> > > > & __that) C++
Neural Network.exe!std::_Tree<std::_Tmap_traits<std::reference_wrapper<neuralnetwork::IConnection const >,double,neuralnetwork::_CPerceptronComparator,std::allocator<std::pair<std::reference_wrapper<neuralnetwork::IConnection const > const ,double> >,0> >::find(const std::reference_wrapper<neuralnetwork::IConnection const > & _Keyval) Line 1553 C++
Neural Network.exe!neuralnetwork::CPerceptron::inputEvent(const neuralnetwork::IConnection * origin, double value) Line 94 C++
请注意,如果我调试地图,它应该包含一个元素。 (或者至少它的大小告诉我它有 1 个元素。)
无论我使用什么类型的迭代来遍历地图,它都会在第一次查询时出错。我使用 Visual Studio 2013。
我现在真的很无助。
抱歉,格式错误。
【问题讨论】:
此时的堆栈跟踪是什么? 您可能有兴趣知道_CPerceptronComparator
不是您在C++ 中使用的合法标识符。保留以下划线和大写字母开头的名称。
您发布的代码看起来不错,不应该给您堆栈溢出。您的问题很可能出在其他地方,可能是缓冲区溢出或写入某处的无效引用正在破坏堆栈。
添加了更多信息。我只是为新读者注意它,所以他们不会立即转身。
您是在堆栈上声明大型数组吗?这可能会触发溢出。
【参考方案1】:
问题是由无限循环引起的(实际上我见过的堆栈溢出的唯一原因)。
void CPerceptron::addInputConnection( IConnection * inConn )
m_outConnections.insert( std::ref(*inConn) );
m_inputValues.insert( std::pair<std::reference_wrapper<IConnection>, float64_t>( std::ref( *inConn ), 0.0f ) );
m_isInputReady.insert( std::pair<std::reference_wrapper<IConnection>, bool>( std::ref( *inConn ), false ) );
我在一个名为 addInputConnection 的函数中插入到 m_outConnections 中,该函数在图中(在神经网络中)创建了一个圆圈,因此传播结果导致了无限循环(传播函数不在帖子中)。
这是一个很好的例子,说明这么容易错过这么小的东西,但在其他方面无用的帖子。删除它 IMO。
【讨论】:
【参考方案2】:我已经获取了您的代码并创建了一个可以编译和运行的模型。如果在 gcc 4.8.1 下编译失败,无法进行模板替换。预感这与引用包装器的使用有关(并且您使用的是不同的编译器和标准库),我为 IConnection 类定义了一个 operator
你可以看到code in coliru here。
#include <iostream>
#include <map>
#include <stdexcept>
typedef double float64_t;
namespace neuralnetwork
class IConnection
float64_t _value = 0.0;
public:
IConnection( float64_t v ) : _value(v)
float64_t get() const return _value;
friend inline bool operator< ( const IConnection & lhs, const IConnection & rhs ) return lhs.get() < rhs.get();
;
class CPerceptron
std::map<const IConnection, float64_t>
m_inputValues, m_isInputReady;
public:
void inputEvent(const neuralnetwork::IConnection * origin, double value);
void addInputConnection( IConnection * inConn );
;
void CPerceptron::addInputConnection( IConnection * inConn )
m_inputValues.insert( std::pair<IConnection, float64_t>( *inConn, 0.0f ) );
// namespace neuralnetwork
void neuralnetwork::CPerceptron::inputEvent(const neuralnetwork::IConnection * origin, double value)
std::map< const neuralnetwork::IConnection, float64_t >::iterator
it = m_inputValues.find( *origin );
if ( it == m_inputValues.end() )
throw std::runtime_error("Some error");
// ...
int main( int argc, char *argv[] )
neuralnetwork::IConnection ic( 1.0 );
neuralnetwork::CPerceptron cp;
cp.addInputConnection( & ic );
cp.inputEvent( & ic, 2.0 );
std::cout << "No stack overflow here!" << std::endl;
return 0;
这是我得到的输出
g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
No stack overflow here!
更新:
根据 OP 的观察,我创建了两个使用对象地址在地图中排序的版本:
在堆栈上创建的对象(失败):
http://coliru.stacked-crooked.com/a/02d1f262a75b1d25
在堆上创建的对象(失败):
http://coliru.stacked-crooked.com/a/728cf77040143f21
STL 将有序映射实现为二叉树,它使用复制构造函数将您的对象复制到映射中(二叉树)。它使用您提供的比较器(或运算符
使用 std::shared_ptr 有效(增加了一层间接性)。他们说计算机科学中的任何问题都可以通过一级间接来解决 - 似乎在这里有效。
http://coliru.stacked-crooked.com/a/6aa631675133289b
更新 2:
更简单,去掉get()
函数,使用指向对象的指针作为map中的key,直接比较指针比operator<
中的小于:
http://coliru.stacked-crooked.com/a/f1376a39c8b287df
【讨论】:
可悲的是,即使它有效,它也不好。你按价值排序,我想按堆中的地址排序。值会发生变化——它会在每个学习周期中发生变化,毕竟这将是一个神经网络——并且在将对象放入地图后改变操作员的行为将造成严重的后果问题。 @user2741959 啊,对不起,我错过了。这可能是错误的线索,实际上,让我考虑一下。 让我注意到您定义运算符的解决方案 @user2741959 STL 将有序的map
实现为二叉树,它使用复制构造函数将您的对象复制到映射中(二叉树)。它使用您提供的比较器(或运算符
更新 1 无效,更新 2 是正确的,但是我按照您的描述实现了 operator”作为指针是不确定的,正如我后来在互联网上发现的那样。无论如何请不要打扰,代码已经完美运行。以上是关于在 std::map 中搜索时堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章