带有 std unordered_map 的 SIGFPE

SIGFPE with std unordered map

下面是一个简单的应用程序,如果我在 main.cc.

中取消注释提到的行,它会导致我出现 SIGFPE

config.h

#ifndef SRC_CONFIG_H_
#define SRC_CONFIG_H_

#include <cstdint>
#include <unordered_map>
#include <string>
#include <tuple>
#include <vector>

using ConfigTable_t = std::unordered_map<uint16_t, std::tuple<std::string, std::vector<uint8_t> > >;

static const ConfigTable_t gTable1 {
  { 0x100, std::make_tuple( "table1", std::vector<uint8_t> { 5,5,5,5,5,5 } ) }
};

static const ConfigTable_t gTable2 {
  { 0x200, std::make_tuple( "table2", std::vector<uint8_t> { 0,1,2,3,4,5 } ) }
};

const ConfigTable_t & getConfigTable();

#endif

table_provider.cc

#include "config.h"

const ConfigTable_t & getConfigTable() {
    return gTable1;
}

main.cc

#include "config.h"

static const uint16_t gId = 0x100;
// static const std::string gName = std::get<0>(getConfigTable().at(gId)); //  <-- Doesn't work
static const std::string gName = std::get<0>(gTable1.at(gId));             //  <-- Works  

int main() {
  return 0;
}

中有一个与此问题相关的指针,但我不明白为什么会这样。

我用

编译

g++ -std=c++14 main.cc table_provider.cc -o test

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609

此代码存在 static initialization order fiasco。当您初始化 main.cc 翻译单元中的 gName 时,table_provider.cc 翻译单元中的 gTable1 可能未被初始化。请注意,由于 gTable1 是在头文件中声明的 static 变量,因此每个翻译单元都有一个单独的实例。所以直接访问它和使用getConfigTable会引用不同的对象。

你有一个 static initialization order fiasco.

不要将定义放在 header 文件中,因为这会导致每个 translation unit 将在头文件中定义自己的变量副本。

这意味着 getConfigTable 返回的 gTable1 将不同于 main.cc 文件中定义的 gTable1。还有那个 gTable1 在你使用的时候可能还没有初始化。

解决方案是将全局变量放在一个单个翻译单元(源文件)中。或者更好的是,根本没有全局变量。