簡體   English   中英

在這種情況下如何防止 ODR 違規?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM