問題タブ [one-definition-rule]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - クラスメンバアクセス式に関する1つの定義規則
N4296、3.2 [basic.def.odr]p3:
x
名前が潜在的に評価される式として表示される変数は、左辺値から右辺値への変換を適用して、自明でない関数を呼び出さない定数式を生成しない限り、ex
によって ODR 使用されます。左辺値から右辺値への変換が に適用されるか、または破棄された値の式である、式 の潜在的な結果のセット。ex
x
x
ex
e
e
e
この段落をどう説明する?2つの説明が見つかりました。
ここから 1 「C++14 で [basic.def.odr]/2 を理解しようとしています (N4140)」
これをいくつかのステップに分けてみましょう: 式 `ex` 内の変数 `x` の出現は、次の場合を除き、odr-use を構成します:
ex
潜在的に評価されていないか、または- 次のすべてを満たす必要があります。
- 「左辺値から右辺値への変換を適用する
x
と、重要な関数を呼び出さない定数式が生成されます」 および- "
ex
は、式の潜在的な結果のセット " の要素でありe
、 次のいずれかが成り立ちます:
- "左辺値から右辺値への変換が適用される
e
"- 「または
e
破棄値式です」
および cppreference http://en.cppreference.com/w/cpp/language/definitionからの 2
次のいずれかが真でない限り
x
、潜在的に評価される式の変数ex
は ODR 使用されます。
左辺値から右辺値への変換を適用する
x
と、重要な関数を呼び出さない定数式が生成されます
x
はオブジェクトであり、 ex はより大きな式の潜在的な結果の 1 つですe
。ここで、そのより大きな式は、破棄された値の式または左辺値から右辺値への変換のいずれかです。
2 つのルールについての最初の答えはandで、もう 1 つはanyです。どちらが正しいですか?
このコードを説明するには、ルールをいくつかのステップに分けてください:
c++ - 以下は実際に ODR に違反していますか?
ここから:
この関数は、ODR ([basic.def.odr] §3.2/6) に 2 回違反します。これは、コンストラクター 2 の引数のどちらも左辺値から右辺値への変換を受け取らないためです。したがって、それらはアドレスで渡されますが、const (および constexpr) は内部リンケージを意味するため、アドレスは TU に依存します。
最初はそうだと思ったのですが、問題はmagic_number
内部リンケージです。内部リンケージがあるため、本質的にmagic_number
は、それらが異なる翻訳単位の異なる変数であるかのように扱われ、したがって同じ変数の複数の定義としてではありませんか? C++ 標準の最新のワーキング ドラフトの引用を使用して、誰かがこれを指定できますか?
c++ - インライン関数の ODR 違反を検出する方法はありますか?
だから私は2つの別々の翻訳単位でこのコードを持っています:
正常にコンパイルされると、結果は10
. -O3 (インライン展開) でコンパイルすると、11
.
に対して ODR 違反を行ったことは明らかですfunc()
。
異なるdllのソースをより少ないdllにマージし始めたときに現れました。
私が試してみました:
- GCC 5.1
-Wodr
(必要-flto
) - ゴールドリンカー
-detect-odr-violations
ASAN_OPTIONS=detect_odr_violation=1
アドレス サニタイザーを使用してインストルメント化されたバイナリを実行する前に設定します。
Asan は、他の ODR 違反をキャッチできると思われます (異なるタイプのグローバル変数またはそのようなもの...)
これは C++ の非常に厄介な問題であり、それを検出するための信頼できるツールがないことに驚いています。
おそらく、私が試したツールの 1 つを悪用したのでしょうか? または、これには別のツールがありますか?
編集:
func()
大幅に異なる 2 つの実装を作成しても、同じ量の命令にコンパイルされないため、問題に気付かないままです。
これは、クラス本体内で定義されたクラス メソッドにも影響します。それらは暗黙的にインライン化されます。
多くのコピー/貼り付けとその後の小さな変更を伴うレガシーコードは楽しいものです。
c++ - 1 つの定義規則に関する C++ の混乱
One Definition Ruleについて読んでいました。次のように述べています。
1 つの .cpp ファイルがstruct S { int x;を定義している場合。}; もう 1 つの .cpp ファイルはstruct S { int y;を定義します。}; 、それらをリンクするプログラムの動作は未定義です。これは通常、名前のない名前空間で解決されます。
未定義の理由と方法がわかりませんか?誰かがこの背後にある実際の理由を説明してくれますか? 名前のない名前空間でどのように解決されますか?