[英]How to prevent ODR violations in this case?
disclaimer: this question is about prevention of unintended naming collisions, and make sure the following code fail to compile/link.免责声明:这个问题是关于防止意外的命名冲突,并确保以下代码无法编译/链接。
[edit] actually I'd be happy with something preventing this to compile/link, or something that solves this, like anonymous namespaces. [编辑] 实际上,我很高兴有一些东西可以阻止它编译/链接,或者一些可以解决这个问题的东西,比如匿名名称空间。 But anonymous namespaces aren't supposed to go inside headers.
但是匿名命名空间不应该在标头内 go 。
// Class1.h
// --------
namespace SomeLargeLib {
struct S {
int a;
S() { a = 1; }
};
}
// Class1.cpp
// ----------
#include "Class1.h"
void foo() { SomeLargeLib::S s; }
// Class2.h
// --------
namespace SomeLargeLib {
struct S {
int a;
S() { a = 2; }
};
}
// Class2.cpp
// -----------
#include "Class2.h"
int main() {
SomeLargeLib::S s;
return s.a; // returns 1 !!
}
What happens here is that the ctor S::S has two inline definitions, so the linker is allowed to assume all definitions are the same and pick any one.这里发生的是 ctor S::S 有两个内联定义,因此允许 linker 假设所有定义都相同并选择任何一个。 Note that moving the S::S ctors outside of the classes results in a linker error as they are no longer inline.
请注意,将 S::S ctors 移到类之外会导致 linker 错误,因为它们不再是内联的。
Anyway, since we shouldn't have anonymous namespaces in headers (see C++ Core Guidelines), what should be done to prevent such ODR violations?无论如何,既然我们不应该在标头中使用匿名命名空间(请参阅 C++ 核心指南),那么应该如何防止此类 ODR 违规行为? A linker error would be perfect but the standard says no diagnostic is needed for ODR violations.
linker 错误将是完美的,但标准表示 ODR 违规不需要诊断。
ODR violation are extremely hard to detect automatically, that's why it is ill formed no diagnostic required. ODR 违规非常难以自动检测,这就是为什么它是病态的,不需要诊断。
However, if your goal is to prevent and detect such cases, simply use modules with a strong ownership.但是,如果您的目标是防止和检测此类情况,只需使用具有强所有权的模块即可。 The model completely prevent most (if not all) ODR violations that are hard to detect.
model 完全防止了大多数(如果不是全部)难以检测的 ODR 违规。
Example:例子:
class1.ixx
: class1.ixx
:
export module class1;
namespace SomeLargeLib {
export struct S {
int a;
S() { a = 1; }
};
}
class2.ixx
: class2.ixx
:
export module class2;
namespace SomeLargeLib {
export struct S {
int a;
S() { a = 2; }
};
}
test1.cpp
: test1.cpp
:
import class1;
import <iostream>;
void fun() {
SomeLargeLib::S a;
std::cout << a.a; // 1
}
test2.cpp
: test2.cpp
:
import class2;
import <iostream>;
void fun() {
SomeLargeLib::S a;
std::cout << a.a; // 2
}
And the great thing is that you could link test1.cpp
and test2.cpp
together in the same binary.最棒的是,您可以在同一个二进制文件
test2.cpp
test1.cpp
在一起。 No collision ever happen.永远不会发生碰撞。
However, a compiler error is emitted for test3: test3.cpp
:但是,会为 test3:
test3.cpp
发出编译器错误:
import class1;
import class2; // error: name SomeLargeLib::S already exists, can't import both
Those use cases are supported in MSVC already today.这些用例今天已经在 MSVC 中得到支持。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.