[英]Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations?
[英]How to prevent ODR violations in this case?
免責聲明:這個問題是關於防止意外的命名沖突,並確保以下代碼無法編譯/鏈接。
[編輯] 實際上,我很高興有一些東西可以阻止它編譯/鏈接,或者一些可以解決這個問題的東西,比如匿名名稱空間。 但是匿名命名空間不應該在標頭內 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 !!
}
這里發生的是 ctor S::S 有兩個內聯定義,因此允許 linker 假設所有定義都相同並選擇任何一個。 請注意,將 S::S ctors 移到類之外會導致 linker 錯誤,因為它們不再是內聯的。
無論如何,既然我們不應該在標頭中使用匿名命名空間(請參閱 C++ 核心指南),那么應該如何防止此類 ODR 違規行為? linker 錯誤將是完美的,但標准表示 ODR 違規不需要診斷。
ODR 違規非常難以自動檢測,這就是為什么它是病態的,不需要診斷。
但是,如果您的目標是防止和檢測此類情況,只需使用具有強所有權的模塊即可。 model 完全防止了大多數(如果不是全部)難以檢測的 ODR 違規。
例子:
class1.ixx
:
export module class1;
namespace SomeLargeLib {
export struct S {
int a;
S() { a = 1; }
};
}
class2.ixx
:
export module class2;
namespace SomeLargeLib {
export struct S {
int a;
S() { a = 2; }
};
}
test1.cpp
:
import class1;
import <iostream>;
void fun() {
SomeLargeLib::S a;
std::cout << a.a; // 1
}
test2.cpp
:
import class2;
import <iostream>;
void fun() {
SomeLargeLib::S a;
std::cout << a.a; // 2
}
最棒的是,您可以在同一個二進制文件test2.cpp
test1.cpp
在一起。 永遠不會發生碰撞。
但是,會為 test3: test3.cpp
發出編譯器錯誤:
import class1;
import class2; // error: name SomeLargeLib::S already exists, can't import both
這些用例今天已經在 MSVC 中得到支持。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.