【发布时间】:2017-01-06 00:19:59
【问题描述】:
我有三个文件,main.cpp、a.cpp 和 b.cpp。 main() 函数只是调用 a.cpp 中的一个函数,然后在 b.cpp 中调用一个函数——我得到一个 SIGSEGV。据我所知,与我的 sort() 一起使用的 lambda 函数似乎相互冲突。编译命令行顺序很重要;如果我通过以下方式编译文件:
g++ -std=c++11 main.cpp a.cpp b.cpp
代码崩溃(我得到“*** stack smashing detected ***: ./a.out terminated”),但如果我切换“a.cpp”和“b.cpp”:
g++ -std=c++11 main.cpp b.cpp a.cpp
它运行良好(我并不是说它是否“有效”,只是 SIGSEGV 与无 SIGSEGV)。
这是我可以为这三个文件生成的最小代码示例:
main.cpp:
extern void spud1 (void);
extern void spud2 (void);
int
main (int argc, char **argv)
{
spud1 ();
spud2 ();
}
a.cpp:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
struct Database
{
int pubdate;
string title;
string link;
};
static vector <Database> database;
void
spud1 (void)
{
int i;
for (i = 0; i < 20; i++) {
database.push_back ({});
}
sort(database.begin(), database.end(),
[] (const Database& a, const Database& b)
{
return (a.pubdate > b.pubdate);
});
}
b.cpp:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
struct Database
{
unsigned serial;
double calories;
double carbs;
double sodium;
double sugar;
};
static vector <Database> database;
void
spud2 (void)
{
int i;
for (i = 0; i < 20; i++) {
database.push_back ({});
}
sort(database.begin(), database.end(),
[] (const Database& a, const Database& b)
{
return (a.serial > b.serial);
});
}
有两件事困扰我:
- 工具链中没有任何迹象表明正在发生“坏事”;没有编译器或链接器警告,并且
- 我无法将“
struct Database”设置为模块本地——如果我在它前面加上“static”,我会收到错误:“a.cpp:13:1: error: a storage class can只为对象和函数指定**`"
所以,我的问题是,我做错了什么,我该如何解决? (即,为什么没有警告,这是“应该”发生的吗?如何使我的“数据库”结构实际上是模块的本地结构?-我的解决方法是使用不同的名称,但我不高兴与那个。)
【问题讨论】:
-
如果
.cpp翻译单元应该是私有的,请将struct Database放在未命名的命名空间中。 -
正确。如图所示,代码是最小的可重现测试用例。编译顺序很重要。按照 πάντα ῥεῖ 的建议使用未命名的命名空间是可行的,但我认为这是一个问题——lambda 运算符不应该泄露我的内部(更重要的是,不可导出)对象,对吧?
-
在副本中,尤其是this answer 是最相关的,因为它解释了为什么会发生这种情况(破坏 ODR)。