我很难理解为什么我的代码按照它的方式工作(或者不按照应有的方式工作)。
我尝试编写(在C ++中)一个接口,该接口允许在C中的标准模板库中使用unordered_map
上运行的某些函数。但是,我也想写一个允许在C ++中使用它们的命名空间。
我问的问题不在于如何以不同的方式进行,而是为什么它的工作方式如此;
让我们说一段时间我只需要两个功能:添加元素并写入地图的大小。标题如下:
//project.h
#ifdef __cplusplus
extern "C" {
#endif
void add(int, int);
void give_size();
#ifdef __cplusplus
}
#endif
源代码:
//project.cc
#include <unordered_map>
#include <iostream>
#include "project.h"
using namespace std;
unordered_map<int, int> my_map;
void add(int arg, int val) {
my_map.insert ({{arg, val}});
}
void give_size() {
cout << my_map.size() << endl;
}
C ++的界面:
//cproject
namespace pro {
#include "project.h"
}
和测试:
//test.cc
#include "cproject"
namespace {
unsigned long test() {
::pro::add(1,2);
::pro::add(3,4);
return 0;
}
unsigned long dummy = test();
}
int main() {
::pro::give_size();
return 0;
}
而且,为了完整性,Makefile
:
g++ -Wall -std=c++11 -c -o project.o project.cc
g++ -Wall -std=c++11 -c -o test.o test.cc
g++ test.o project.o -o test
问题当然是运行test
输出0
而不是2
- 这意味着地图会在test
之前的某处消失main
。
我认为它可能是某种static initialization order fiasco,但是我发现附加的解决方案非常有用,因为我没有明确地调用project.cc
文件中的对象在test.cc
。
我很感激对此问题的任何帮助。
答案 0 :(得分:2)
是的,这是命名不佳的静态初始化顺序惨败。命名不佳,因为C ++标准称之为“动态初始化”; “静态初始化”是不同的东西。
这意味着地图在测试的主要
之前的某处消失了
不完全。问题是你在它之前使用地图 ,为它添加值。现在碰巧,对于某些地图实现,零初始化状态(这是在任何动态初始化程序运行之前对所有全局变量执行的操作)与默认构造函数的作用相同。因此,test
中的代码首先执行并尝试向地图添加内容,并且地图的插入函数工作正常,创建节点,设置节点的内部指针等。
然后运行映射的实际默认构造函数,将这些指针重置为null,泄漏并忘记您创建的所有节点。您之前的插入已撤消,地图再次为空。
您链接中提供的解决方案可行;你隐式地通过自由函数调用对象,即使你没有明确地这样做。没有真正的区别。您仍然使用一个函数替换project.cc中的全局my_map
,该函数返回对函数级静态(或指针的引用,具体取决于您选择的确切解决方案)。唯一的区别是,您不是在test.cc中调用此函数,而是在add
和give_size
内调用此函数。
作为旁注,整个全球国家的事情通常都是可疑的。它不是线程安全的,它使得理解程序正在做什么变得更加困难。考虑不要这样做。