問題タブ [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.

0 投票する
1 に答える
111 参照

c++ - ODR で使用される空のクラスの最適化

今日の C++ コードの多くは、テンプレートを最大限にロードする傾向があります。それらはライブラリです: STL、Boost.Spirit、Boost.MPL など。それらは、フォームで機能オブジェクトを宣言することをユーザーに奨励します struct S { /* presence of non-virtual member functions and operators, but absense of non-static data members or non-empty base classes */ }; S const s{};。それらのほとんどはステートレスです (つまりstatic_assert(std::is_empty< S >{});、保持します)。それらのうち、ODR で使用されるものについてはdata、ファイルの空のセクションに関係なく、1 バイトずつ増加します (結果的に割り当てられたオブジェクトのすべてのアドレスが異なる必要があるためsizeof(S) == 1、空のタイプの場合)。SBoost.Spirit の単純な文法でも、このような ODR で使用される空のクラスはたくさんあります。しかし、それらのためにスペースを確保することはまったく意味がありません。

次のコードを使用してclangcoliruでテストしようとしました ( -Ofast):

結果を取得します ( sizeutility forの出力DIM == 100、つまり 100 * 100 クラス):

ODR の使用を抑制するために署名を変更diff(lhs & l, rhs & r)すると、結果は次のようになります。diff(lhs l, rhs r)

data行の単純なコメントの場合 (セクションは重要なだけです) とほぼ同じです (セクションassert((check< DIM >()));の大部分textは予測可能な DCE 最適化アウトです):

したがって、ODR で使用される空のクラスの最適化はないと結論付けます。

明示的に指定されたテンプレート パラメーターには、単純な typefilter を使用する可能性があります。

しかし、推測されたテンプレートの種類に対する簡単な回避策は思い浮かびません。

最新のコンパイラでは、上記の最適化が暗示されていますか? はいの場合、それを有効にする方法は?いいえの場合、現時点で望ましい動作を実現するための手法はありますか?

オブジェクトのアドレスがつぶやくことがあることは知っていますが、上記の状況ではそうではありません。

[[immaterial]]変数や型の属性のようなもの(例)が便利だと思います。おそらく、そのような属性 (クラスに使用される) は、属性付きクラスのインスタンスのアドレスを取得する可能性を否定する必要があります (コンパイル時のハードエラー) か、アドレスの演算子は&意味のない値を返す必要があります (実装定義)。

0 投票する
4 に答える
1413 参照

c++ - クラス static const ODR 内

メンバーstaticのクラス内初期化に少し混乱しています。constたとえば、以下のコードでは:

Live example

定義しませんFoo::n(行はコメント化されています)。f(Foo::n)したがって、リンク時に呼び出しが失敗することを期待していますが、実際にそうです。ただし、次の行std::cout << g(Foo::n) << std::endl;は、.gcc などの最適化フラグを使用するたびに、gcc によってのみ正常にコンパイルおよびリンクされます (clang は依然としてリンカー エラーを出力します) -O1/2/3

  1. 最適化がオンになっている場合、gcc (gcc5.2.0 および gcc 4.9.3 で試行) がコードをコンパイルおよびリンクするのはなぜですか?
  2. そして、クラス内の static const メンバーの唯一の使用法は、呼び出しのようなテンプレート パラメーターなどの定数式であると言うのは正しいh<Foo::n>ですか?その場合、コードはリンクする必要がありますか?
0 投票する
1 に答える
193 参照

c++ - 同じ名前の C++ インライン関数と外部関数が予期しない結果をもたらす

次のコードは、1 つの定義規則に違反していませんが、予期しない結果をもたらしています。

Test.hpp

Test1.cpp

Test2.cpp

main.cpp

「1 99」と出力されることを期待していますが、常に「1 1」と出力されます。

Test::test の 2 つの定義については、そのうちの 1 つがインライン定義であるため、One Definition Rule にも違反していません。

したがって、このプログラムは有効ですが、期待される結果が出力されません...

このプログラムに問題はありますか? それとも、ODR ルールについて誤解しているのでしょうか? (C++ 標準への参照が役立ちます)。

0 投票する
1 に答える
569 参照

c++ - C++ での仮想関数のコンパイル時の静的型チェック

バックグラウンド

最近、私の同僚が、ライブラリの古いバージョンのヘッダー ファイルが使用されているという問題に遭遇しました。その結果、C++ で仮想関数を呼び出すために生成されたコードが、クラスの仮想関数ルックアップ テーブル ( vtable ) 内の間違ったオフセットを参照していました。

残念ながら、このエラーはコンパイル中にキャッチされませんでした。

質問

すべての通常の関数は、正しい関数 (正しいオーバーロード バリアントを含む) がリンカによって選択されるように、マングルされた名前を使用してリンクされます。同様に、オブジェクト ファイルまたはライブラリには、C++ クラスのvtable内の関数に関するシンボリック情報が含まれていると想像できます。

g++リンク中に C++ コンパイラ (または Visual Studio など) が仮想関数の呼び出しを型チェックできるようにする方法はありますか?

簡単なテスト例を次に示します。この単純なヘッダー ファイルと関連する実装を想像してください。

ベース.hpp:

派生.cpp:

ここで、プログラムが間違った/古いバージョンのヘッダー ファイルを使用し、中央の仮想関数が欠落していると想像してください。

BaseWrong.hpp

ここにメインプログラムがあります:

メイン.cpp

正しいヘッダーを使用して「ライブラリ」をコンパイルし、次に間違ったヘッダーを使用してメイン プログラムをコンパイルおよびリンクすると…</p>

…その後、 への仮想呼び出しがvtableh()で間違ったインデックスを使用するため、呼び出しは実際には:g()

この小さな例では、関数g()と関数h()は同じシグネチャを持っているため、「唯一の」問題は間違った関数が呼び出されていることです (これはそれ自体が悪いことであり、完全に気付かれない可能性があります)。たとえば、Pascal 呼び出し規則が使用されている Windows 上の DLL で関数を呼び出す場合 (呼び出し元が引数をプッシュし、呼び出し先が戻る前に引数をポップする)。

0 投票する
1 に答える
118 参照

c++ - static const 整数メンバーの基本的な楽しみ

次のコードを検討してください。

お気に入りのコンパイラを開かずに、この単純な獣をコンパイルしてリンクしようとすると、どのような結果になると思いますか?

コンパイラだけでなく、その最適化オプションにも依存することに驚く人もいるかもしれません! たとえば、gcc では、コードは最適化をオフにするとリンクを拒否しますが、最適化をオンにすると喜んでリンクします (そして runnable-doing-nothing 実行可能ファイルを生成します)。

失敗した場合の診断はおかしいでしょう - シンボルX::iが見つからないでしょう。破棄されるため、最適化が有効なリンクは成功X::iします。

そして質問。このコードをコンパイルするコンパイラの動作は正しいですか? X::iにはリンケージがないので、このシンボルでリンケージを要求するコードを生成するように要求されたときに、コンパイラーは文句を言うべきではありませんか?

0 投票する
1 に答える
1207 参照

c++ - 純粋仮想関数の実装

Scott Meyers の『Effective C++ 』を読んでいて、継承に関するセクションにいます。彼は言った

純粋仮想関数は、インターフェイスの継承のみを指定します。

単純な (不純な) 仮想関数は、インターフェイスの継承と既定の実装の継承を指定します。

ここで、次の 2 つのクラスを考えます。

例で行ったように、純粋な仮想関数のデフォルトの実装を提供し、 を介して呼び出すことができますqualified-function-call-expression。不純な仮想関数についてもほぼ同じことができます

次のように不純な仮想関数を定義しない場合:

それは完全にうまくいくでしょう。

デモ

では、純粋仮想関数の唯一の目的は、クラスを抽象化する (インスタンス化できない) ことですか?