【问题标题】:Segfault when adding an element to a std::map向 std::map 添加元素时出现段错误
【发布时间】:2014-11-26 09:35:18
【问题描述】:

当我尝试在地图中插入一个元素时发生了一些奇怪的事情

main.cpp

S3Wrapper wrapper = S3Wrapper::getS3Wrapper();
int main(){
    return 0;
}

所以基本上只为 S3Wrapper 调用单例

S3Wrapper.hpp

class S3Wrapper
{
    S3Wrapper(std::string bucketName);
public:
    ~S3Wrapper();
    static S3Wrapper   &getS3Wrapper(std::string name = BUCKET_NAME);
}

和 S3Wrapper.cpp

static std::map<std::string, S3Wrapper*> _wrapperMap;
S3Wrapper&  S3Wrapper::getS3Wrapper(std::string name)
{
    auto it = _wrapperMap.find(name);
    if (it == _wrapperMap.end())
    {
        auto t = new S3Wrapper(name);
        _wrapperMap[name] = t;
        return *(_wrapperMap[name]);
    }
    return *(it->second);
}

当我编译时我没有任何错误/警告,但是程序段错误:

g++ main.cpp S3Wrapper.cpp -std=c++0x -ls3 -g3

gdb 的结果

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7937c4a in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0  0x00007ffff7937c4a in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x0000000000406295 in std::_Rb_tree_iterator<std::pair<std::string const, S3Wrapper*> >::operator-- (this=0x7fffffffd8b0) at /usr/include/c++/4.8/bits/stl_tree.h:204
#2  0x00000000004061f7 in std::_Rb_tree<std::string, std::pair<std::string const, S3Wrapper*>, std::_Select1st<std::pair<std::string const, S3Wrapper*> >, std::less<std::string>, std::allocator<std::pair<std::string const, S3Wrapper*> > >::_M_get_insert_unique_pos (this=0x60b580 <_wrapperMap>, __k=...) at /usr/include/c++/4.8/bits/stl_tree.h:1333
#3  0x00000000004058f5 in std::_Rb_tree<std::string, std::pair<std::string const, S3Wrapper*>, std::_Select1st<std::pair<std::string const, S3Wrapper*> >, std::less<std::string>, std::allocator<std::pair<std::string const, S3Wrapper*> > >::_M_get_insert_hint_unique_pos (this=0x60b580 <_wrapperMap>, __position=..., __k=...) at /usr/include/c++/4.8/bits/stl_tree.h:1425
#4  0x000000000040511c in std::_Rb_tree<std::string, std::pair<std::string const, S3Wrapper*>, std::_Select1st<std::pair<std::string const, S3Wrapper*> >, std::less<std::string>, std::allocator<std::pair<std::string const, S3Wrapper*> > >::_M_emplace_hint_unique<std::piecewise_construct_t const&, std::tuple<std::string const&>, std::tuple<> >(std::_Rb_tree_const_iterator<std::pair<std::string const, S3Wrapper*> >, std::piecewise_construct_t const&, std::tuple<std::string const&>&&, std::tuple<>&&) (this=0x60b580 <_wrapperMap>, __pos=...) at /usr/include/c++/4.8/bits/stl_tree.h:1673
#5  0x0000000000404d24 in std::map<std::string, S3Wrapper*, std::less<std::string>, std::allocator<std::pair<std::string const, S3Wrapper*> > >::operator[] (this=0x60b580 <_wrapperMap>, __k=...)
    at /usr/include/c++/4.8/bits/stl_map.h:465
#6  0x0000000000404945 in S3Wrapper::getS3Wrapper (name=...) at S3Wrapper.cpp:55
#7  0x00000000004021e3 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at main.cpp:8
#8  0x00000000004022ce in _GLOBAL__sub_I_wrapper () at main.cpp:41
#9  0x0000000000406b7d in __libc_csu_init ()
#10 0x00007ffff7308e55 in __libc_start_main (main=0x401edc <main()>, argc=1, argv=0x7fffffffdc28, init=0x406b30 <__libc_csu_init>, fini=<optimized out>, rtld_fini=<optimized out>, 
    stack_end=0x7fffffffdc18) at libc-start.c:246
#11 0x0000000000401b79 in _start ()

第 55 行:_wrapperMap[name] = t;

如果我将 t 插入向量中,我没有任何问题

【问题讨论】:

    标签: c++ stdmap


    【解决方案1】:

    这是静态初始化的惨败:在不同翻译单元中定义的静态变量以未指定的顺序初始化,因此无法保证 _wrapperMapwrapper 的初始化需要它之前被初始化。

    最好的解决方案是避免使用静态/全局变量。它们通常只会造成麻烦。

    如果你真的想要全局状态,更安全的选择是使用局部静态变量:

    std::map<std::string, S3Wrapper*> & wrapperMap() {
        static std::map<std::string, S3Wrapper*> map;
        return map;
    }
    

    这保证在第一次调用函数时被初始化,因此在初始化之前使用映射没有危险。当静态变量在程序结束时被销毁时,您可能仍然会遇到问题。

    请注意,_wrapperMap 是保留的(在全局命名空间中),因此您应该选择不带前导下划线的名称,或者将其放在命名空间中。

    【讨论】:

    • Singleton 是解决静态初始化失败的一种方法……不是吗。但我同意“最好的解决方案是避免静态/全局变量”
    • 好的,谢谢,我不知道。但你是对的,我会想办法避免使用静态/全局变量。
    【解决方案2】:

    非常感谢 Mike 的解释对我有很大帮助。

    在我的情况下,我无法轻易摆脱静态初始化:所以我只是更改了在 Makefile 中链接的目标文件的顺序,这就解决了我的问题!不确定链接器的顺序是否可以依赖(我正在使用 GCC)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多