map<string, int> 从 const 函数调用时会抛出 std::out_of_range

map<string, int> throws std::out_of_range when called from const function

本文关键字:std out of range 函数调用 string lt int gt map const      更新时间:2023-10-16

从一个不改变其对象状态的函数中注意到使用std::map时的特殊行为:

std::map<std::string, int> _attribLocations;
...
int ProgramInfo::getAttribLocation(const std::string& name) const
{
    return _attribLocations.at(name);
}

当我调用这个函数,传递一个字符串文字时,查找会抛出out_of_range异常:

auto index = info.getAttribLocation("v_position");

我注意到at()有两个版本,一个使用const_iterator,另一个不使用:

mapped_type& at(const key_type& _Keyval)
        {   // find element matching _Keyval
        iterator _Where = _Mybase::lower_bound(_Keyval);
        if (_Where == _Mybase::end()
            || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode())))
            _Xout_of_range("invalid map<K, T> key");
        return (_Where->second);
        }
    const mapped_type& at(const key_type& _Keyval) const
        {   // find element matching _Keyval
        const_iterator _Where = _Mybase::lower_bound(_Keyval);
        if (_Where == _Mybase::end()
            || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode())))
            _Xout_of_range("invalid map<K, T> key");
        return (_Where->second);
        }
    };

看起来导致它抛出的部分是:

_Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode()))

我没有真正调试过比这更深入的东西。

我使用的是Visual Studio 2015。

我确信正在传递的密钥确实存在于映射中(通过使用调试器检查映射)。这可能是映射实现中的一个错误,或者我在比较字符串时遗漏了一些内容?

啊,愚蠢的错误!事实证明,存储在我的映射中的键被填充了终止字符(它们有数千个字符长,大部分是"\0")。我传入了字符串文字,比如"gl_position",但查找实际上没有找到任何内容。我在非常数函数中使用了[]运算符,它返回默认的int(0),这正是我所期望的。但是at()未能找到该值,并引发了。以下是发生的事情:

class A
{
public:
    A()
    {
        char* foo = (char*)malloc(40000);
        foo[0] = 'f';
        foo[1] = 'o';
        foo[2] = 'o';       
        for (int i = 3; i < 40000; i++)
            foo[i] = '';
        std::string fooStr(foo, 40000);
        map[fooStr] = 5;
    }

    int getAttribLocation(const std::string name) 
    {
        return map[name];
    }
private:
    std::map<std::string, int> map;
};
int main()
{
    A instance;
    auto x = instance.getAttribLocation("foo");
    return 0;
}

混淆来自于在[]和at()之间的切换,因为我不能在常量函数中使用[]。