下面是长篇解释,问题在底部。
我的问题特别提到当前的C ++草案标准(但也是当前的'主要'标准)here。更具体地说,关于成员职能和ODR,第3.2节第6节(第35页)陈述each definition of D shall consist of the same sequence of tokens
。
我最近在添加新数据分析时在项目中遇到了以下问题。
我正在写一个文件,A.cpp。我创建了一个小的虚拟结构来保存一些数据。在此示例中,我将其称为Data
。
namespace Example {
struct Data {
//etc
};
//Use Data
};
但是在另一个文件B.cpp中,Data
命名空间内已经有一个名为Example
的结构体。编译器为这两个类生成Data::~Data();
,这两个类又调用其各自成员的析构函数。 B.cpp中的定义包含一个向量,当使用A.cpp中定义的布局在Data
结构上调用时,该向量会导致爆炸。虽然两个结构似乎都能正常工作,没有编译时错误,但在链接时链接器会选择一个定义并使用它,忽略另一个定义。 (因此导致A.cpp内的Data
个物体发生爆炸)
GCC或MSVC下未发出任何警告。 启用优化后,问题不会发生(函数内联,没有链接时间混淆)。
我的问题是,标准只表明行为未定义If D is a template and is defined in more than one translation unit
。
要么我误解了标准,要么允许未定义的行为无声地发生;或者GCC和MSVC都默默地接受他们不应该接受的东西(并且应该拒绝产生输出或发出警告)(当前情况是未定义的,没有诊断的行为不一致)。
有人可以帮助我理解这与不在类中定义的函数的冲突定义有什么不同(这会导致警告/错误)。
答案 0 :(得分:3)
有人可以帮助我理解这与不在类中定义的函数的冲突定义有什么不同(这会导致警告/错误)。
不同之处在于,类中的函数定义隐式名义上是 inline ,如果函数再次遇到,它会禁止编译器警告。这并不意味着编译器必须内联它们 - 它可能决定使用任何启发式方法来打扰,或者它可能很简单,从不在某些优化级别内联。无论如何,如果您链接的代码看到了名义上内联非成员函数的不同定义,那么您就会遇到完全相同的问题。
见3.2 / 6
在程序中可以有多个类类型 ...的定义,前提是每个定义出现在不同的翻译单元中,并且定义满足以下要求。
- D的每个定义应由相同的令牌序列组成;和
[其他要求]
更一般地说,您应该将代码放入匿名命名空间 ......它们旨在防止此类交叉翻译单元问题。
答案 1 :(得分:0)
什么是多重定义并不重要,它是未定义的行为。未定义的行为可以导致任何结果 - 包括没有来自编译器或运行时的诊断的工作程序。以两种不同的方式定义相同的名称不是格式良好的代码,无论它是成员函数,自由函数,结构或类,全局变量等。