在std::map中搜索时堆栈溢出

stack overflow when searching in std::map

本文关键字:堆栈 搜索 栈溢出 std map      更新时间:2023-10-16

此代码在运行时由于某些原因导致堆栈溢出异常:

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。

我现在真的很无助。

很抱歉格式不正确。

问题是由无限循环引起的(事实上,这是我见过的堆栈溢出的唯一原因)。

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.

我已经获取了您的代码,并创建了一个可以编译和运行的模型。如果未能根据gcc 4.8.1进行编译,则无法进行模板替换。有一种预感,这与引用包装器的使用有关(并且您正在使用不同的编译器和标准库),我定义了一个运算符<对于类IConnection,并删除了包装器和_CPerceptronComparator。它已编译,并且似乎正在运行。

你可以在这里看到coliru中的代码。

#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()函数,使用指向对象的指针作为映射中的键,直接比较指针的值小于operator<:

http://coliru.stacked-crooked.com/a/f1376a39c8b287df