10

12.6.1-明示的な初期化

struct complex {
  complex();
  complex(double);
  complex(double,double);
};

complex sqrt(complex,complex);

complex g = { 1, 2 };  // construct complex(1, 2) 
                       // using complex(double, double) 
                       // and *copy/move* it into g

8.5イニシャライザー

14-フォームで発生する初期化

T x = a;

引数の受け渡し、関数の戻り、例外のスロー(15.1)、例外の処理(15.3)、および集約メンバーの初期化(8.5.1)は、コピー初期化と呼ばれます。[注:コピー初期化により、移動(12.8)が呼び出される場合があります。—エンドノート]

15-フォームで発生する初期化

T x(a);

T x{a};

また、新しい式(5.3.4)、static_cast式(5.2.9)、関数表記型変換(5.2.3)、およびベースとメンバーの初期化子(12.6.2)は、直接初期化と呼ばれます

8.5.4リストの初期化[dcl.init.list]

1-リスト初期化は、braced-init-listからのオブジェクトまたは参照の初期化です。このような初期化子は初期化子リストと呼ばれ、リストのコンマ区切りの初期化子句は初期化子リストの要素と呼ばれます。初期化子リストが空の場合があります。リストの初期化は、直接初期化またはコピー初期化のコンテキストで発生する可能性があります。直接初期化コンテキストでのリスト 初期化は直接リスト初期化と呼ばれ、コピー初期化コンテキストでのリスト初期化はコピーリスト初期化と呼ばれます。

アトミックの問題

29.6.5アトミックタイプの操作の要件[atomics.types.operations.req]

#define ATOMIC_VAR_INIT(value)下記参照

マクロは、値と初期化互換性のあるタイプの静的ストレージ期間のアトミック変数の定数初期化に適したトークンシーケンスに展開されます。[注:この操作では、ロックを初期化する必要がある場合があります。— end note]初期化される変数への同時アクセスは、アトミック操作を介しても、データ競合を構成します。[ 例:

atomic<int> v = ATOMIC_VAR_INIT(5);

前のセクションによると、§12.8.31と§12.8.32に従って省略されたとしても、コピーコンストラクタが関与しない代入の初期化はあってはならないようですが、アトミックは次のように定義されています。

29.5原子タイプ[atomics.types.generic]

atomic() noexcept = default;
constexpr atomic(T) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
T operator=(T) volatile noexcept;
T operator=(T) noexcept;

コピーコンストラクターはありません!

多くの場合、中ATOMIC_VAR_INIT括弧の初期化のために中括弧の式に展開されますが、atomic<int> v = {5}それでも代入の初期化であり、一時的なものを直接作成した後のコピーの作成を意味します。

「定数初期化」セクションを調べて、コピーなしでこれを可能にする抜け穴があるかどうかを確認しました(「マクロは、あるタイプの静的ストレージ期間のアトミック変数の定数初期化に適したトークンシーケンスに展開されるため」初期化-値と互換性があります」)が、私はすでにあきらめています。

関連する議論:

http://thread.gmane.org/gmane.comp.lib.qt.devel/8298

http://llvm.org/bugs/show_bug.cgi?id=14486

編集

控除プロセスを構築しながら、関連する標準セクションを引用する回答が理想的です。

結論

したがって、Nicol Bolasによる良い答えの後、面白い結論はcomplex g = { 1, 2 }、標準が示唆しているコピー(コピーリスト初期化は直接リスト初期化のように解決される)ではないコピー(コピー初期化コンテキスト)であるということです。コピー操作があります(12.6.1:) ...and copy/move it into g

修理

プルリクエスト:https ://github.com/cplusplus/draft/pull/37

4

2 に答える 2

11
complex g = { 1, 2 };  // construct complex(1, 2) 
                       // using complex(double, double) 
                       // and *copy/move* it into g

これは真実ではありません。そして、私はコピー/移動が排除されると言っているのではありません。つまり、コピーや移動はありません。

コピー初期化T x = a;として定義されている8.5p14を引用しました。これは本当です。しかし、次に、初期化が実際にどのように機能するかを定義します。

8.5から、p16:

初期化子のセマンティクスは次のとおりです。デスティネーションタイプは初期化されるオブジェクトまたは参照のタイプであり、ソースタイプは初期化式のタイプです。イニシャライザが単一の(場合によっては括弧で囲まれた)式でない場合、ソースタイプは定義されていません。

  • イニシャライザが(括弧で囲まれていない)braced-init-listの場合、オブジェクトまたは参照はリストで初期化されます(8.5.4)。

その権利は、コピー初期化ルールがbraced-init-listに適用されないことを意味します。8.5.4で説明されているように、これらは別個のルールセットを使用します。

コピーリスト初期化T x = {...};として定義されている8.5.4を引用しました。あなたの推論がうまくいかないのは、copy-list-initializationが実際に何をしているのかを調べたことがないということです。コピーはありません。それはまさにそれが呼ばれているものです。

copy-list-initializationは、 list -initializationのサブセットです。したがって、8.5.4、p3で規定されているすべてのルールに従います。それらは数ページの長さなので、ここでは引用しません。complex g = {1, 2};ルールがどのように適用されるかを順番に簡単に説明します。

  1. イニシャライザリストには要素があるため、このルールはカウントされません。
  2. complexは集計ではないため、このルールはカウントされません。
  3. complexはの専門ではないinitializer_listため、このルールはカウントされません。
  4. 適用可能なコンストラクターは、13.3および13.3.1.7の規則に従って、過負荷解決を介して検討されます。これにより、2つのdoubleを取るコンストラクターが見つかります。

したがって、一時的なものは作成されたり、コピー/移動されたりすることはありません。

copy-list-initializationdirect-list-initializationの唯一の違いは、13.3.1.7、p1に記載されています。

[...] copy-list-initializationで、明示的なコンストラクターが選択されている場合、初期化の形式が正しくありません。

それがとの唯一の違いです。これらは両方ともの例であり、明示的なコンストラクターを使用することを除いて、統一された方法で機能します。complex g{1, 2}complex g = {1, 2}list-initialization

于 2012-12-04T00:52:50.287 に答える
8

constructor-from-Tは明示的ではなく、copy-list-initialization は copy-initialization と同じではありません。どちらも「コンストラクターが考慮される」原因となりますが、コピー初期化は常にコピーコンストラクターを「考慮」しますが、リスト初期化はリスト要素 (およびいくつかの詳細) が入力されたコンストラクターを考慮します。ウィット:

struct Foo
{
    Foo(int) {}
    Foo(Foo const &) = delete;
};

int main()
{
    Foo f = { 1 };  // Fine
}

(コンストラクターが の場合、これは失敗しexplicitます。また、Foo x = 1;コピー コンストラクターが削除されているため、もちろん失敗します。)

おそらく、さらに啓発的な使用例:

Foo make() { return { 2 }; }

void take(Foo const &);
take(make());

これに必要なものはすべて 8.5.4/3 と 13.3.1.7/1 にあります。

于 2012-12-03T23:58:27.597 に答える