在 main 之前使用来自不同文件的变量
Using a variable from a different file before main
我有点难以理解为什么我的代码按它的方式工作(或不按它应该的方式工作)。
我正在尝试编写(在 C++ 中)一个接口,该接口允许使用 C 中标准模板库中一些在 unordered_map
上运行的函数。但是,我还想编写一个名称空间也允许在 C++ 中使用它们。
我要问的不是如何以不同的方式处理它,而是为什么它会这样工作;
暂时说一下,我只需要两个功能:添加元素和写地图的大小。 header 如下:
//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
- 这意味着地图在 [=17= 之前的某处消失了]的main
.
我认为它可能是某种 static initialization order fiasco,但是我发现附加的解决方案不是很有用,因为我没有明确地从 [=22= 中调用 objects ] 文件在 test.cc
.
如果能帮助解决这个问题,我将不胜感激。
是的,这是命名不当的静态初始化顺序失败。命名不当,因为 C++ 标准称它为 "dynamic initialization"; "static initialization" 有点不同。
which means that the map disappears somewhere before the test's main
不完全是。问题是您在地图 存在 之前使用地图,向其添加值。现在碰巧对于某些 map 实现,零初始化状态(这是在任何动态初始化器 运行 之前对所有全局变量所做的)与默认构造函数所做的相同。所以test
中的代码首先被执行并尝试向地图添加东西,地图的插入功能工作得很好,创建节点,设置节点的内部指针等
然后是映射 运行 的实际默认构造函数,将这些指针重置为空,泄漏并忘记您创建的所有节点。您之前的插入已撤消,地图再次为空。
您 link 中提供的解决方案可以工作;你通过自由函数隐式地调用对象,即使你没有明确地这样做。没有真正的区别。您仍然将 project.cc 中的全局 my_map
替换为 returns 对函数级静态(或指针,具体取决于您选择的确切解决方案)的引用的函数。唯一的区别是您不是从 test.cc 中调用此函数,而是从 add
和 give_size
.
中调用此函数
附带说明一下,整个全局状态的事情通常相当可疑。它不是线程安全的,并且使理解程序正在做什么变得更加困难。考虑完全不这样做。
我有点难以理解为什么我的代码按它的方式工作(或不按它应该的方式工作)。
我正在尝试编写(在 C++ 中)一个接口,该接口允许使用 C 中标准模板库中一些在 unordered_map
上运行的函数。但是,我还想编写一个名称空间也允许在 C++ 中使用它们。
我要问的不是如何以不同的方式处理它,而是为什么它会这样工作;
暂时说一下,我只需要两个功能:添加元素和写地图的大小。 header 如下:
//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
- 这意味着地图在 [=17= 之前的某处消失了]的main
.
我认为它可能是某种 static initialization order fiasco,但是我发现附加的解决方案不是很有用,因为我没有明确地从 [=22= 中调用 objects ] 文件在 test.cc
.
如果能帮助解决这个问题,我将不胜感激。
是的,这是命名不当的静态初始化顺序失败。命名不当,因为 C++ 标准称它为 "dynamic initialization"; "static initialization" 有点不同。
which means that the map disappears somewhere before the test's main
不完全是。问题是您在地图 存在 之前使用地图,向其添加值。现在碰巧对于某些 map 实现,零初始化状态(这是在任何动态初始化器 运行 之前对所有全局变量所做的)与默认构造函数所做的相同。所以test
中的代码首先被执行并尝试向地图添加东西,地图的插入功能工作得很好,创建节点,设置节点的内部指针等
然后是映射 运行 的实际默认构造函数,将这些指针重置为空,泄漏并忘记您创建的所有节点。您之前的插入已撤消,地图再次为空。
您 link 中提供的解决方案可以工作;你通过自由函数隐式地调用对象,即使你没有明确地这样做。没有真正的区别。您仍然将 project.cc 中的全局 my_map
替换为 returns 对函数级静态(或指针,具体取决于您选择的确切解决方案)的引用的函数。唯一的区别是您不是从 test.cc 中调用此函数,而是从 add
和 give_size
.
附带说明一下,整个全局状态的事情通常相当可疑。它不是线程安全的,并且使理解程序正在做什么变得更加困难。考虑完全不这样做。