2

重複では、少なくとも私の質問のポイント14に対する答えはありません。そして、それらは最も重要です。他の点は削除できますが、質問全体を閉じないようにお願いします。

1.以下のコードでは、obj1 が正常に作成されます。しかし、obj2 と obj3 の作成のコメントを外そうとすると、コンパイル (-std=c++11、g++ 4.9.2) は失敗します。なぜそうなのですか?オブジェクトのメモリがスタックに割り当てられているかヒープに割り当てられているかに関係なく、初期化は同じように実行する必要があると考えました。


struct C
{
    int c;

    C() = delete;
};

int main()
{   
    C obj1 { };

    C *obj2 = (C *) malloc(sizeof(C));
    //new ((void *) obj2) C{ };

    //C* obj3 = new C{ };

    return 0;
}

2.標準に従って、2 種類の動作 (obj1-case または obj2,obj3-cases) のどちらが正しいかを理解しようとしました。標準では次のように述べられています (#3242 および #3337、8.5.4):

型 T のオブジェクトまたは参照のリスト初期化は、次のように定義されます。

— 初期化子リストに要素がなく、T が既定のコンストラクターを持つクラス型の場合、オブジェクトは値で初期化されます。

わかった。そこで、値の初期化の定義に進みます (#3242 および #3337、8.5.0):

T が (おそらく cv 修飾された) 非共用体クラス型であり、ユーザー提供のコンストラクターがない場合、オブジェクトはゼロで初期化され、T の暗黙的に宣言された既定のコンストラクターが自明でない場合、そのコンストラクターが呼び出されます。

(#3242, 12.1)によると

デフォルトのコンストラクターは、ユーザーが提供したものでも削除されたものでもない場合、自明です。. .

したがって、削除されたデフォルトのコンストラクターは自明ではないため、コードC obj1 { }; コンパイルに失敗するはずです。

しかし、(#3337、12.1)によると

デフォルトのコンストラクターは、それがユーザーによって提供されておらず、次の場合には自明です。. .

したがって、削除されたデフォルトのコンストラクターは、コードC obj1 { };の自明なものです。コンパイルに成功するはずです。

真実はどこにある?

3.しかし、それだけではありません。標準の次のバージョンでは、次のように述べられています (# 3367、8.5.4):

型 T のオブジェクトまたは参照のリスト初期化は、次のように定義されます。

— T が集合体の場合、集合体の初期化が実行されます

— それ以外の場合、初期化子リストに要素がなく、T が既定のコンストラクターを持つクラス型である場合、オブジェクトは値で初期化されます。

私が理解しているように、 Cは集約です。しかし、ここで問題があります。削除されたデフォルト コンストラクターを持つ集計がどのように作成されるかについての情報が見つかりませんでした。8.5.1 Aggregatesにはそのような情報はありません。しかし、これによると

8.5.4 で指定されているように、初期化子リストによって集合体が初期化されると、初期化子リストの要素は、添え字またはメンバーの昇順で、集合体のメンバーの初期化子として取得されます。各メンバーは、対応する initializer-clause からコピー初期化されます。. . (#3367、8.5.1)

[集約の場合にコンパイラで生成された]コンストラクターは、集約の初期化中に無視されるだけだと思います。したがって、削除されたデフォルトのコンストラクターも単純に無視され、C obj { };と推測できます。正常にコンパイルされるはずですが、デフォルトのコンストラクターが削除されたオブジェクトを作成するのは奇妙です。それでも、私が正しく理解していれば、このバージョンの標準 obj1-case によれば、大丈夫であり、obj2、obj3-cases がコンパイルに失敗するのは間違っています。私は正しいですか?

4.論理的な問題は、とにかく、どの標準バージョン #3242/#3337 または #3367 を信頼すべきかということです。バージョン #3367 は 2012 年に作成されたので 2011 年よりも遅く、c++11 と呼べるかどうかはわかりません。どのバージョンが真の C++11 標準と見なされますか? g++ 4.9.2 を使用して上記のコード例をコンパイルしました。コンパイラが使用する標準バリアントは何ですか? どうすれば知ることができますか? バージョン #3337 または #3367 が大きく異なるためです。

たとえば、#3367 では、値の初期化の定義が劇的に変更されました。

タイプ T のオブジェクトを値で初期化するとは、次のことを意味します。

— T が (おそらく cv 修飾された) クラス型 (第 9 節) であり、デフォルト コンストラクターがない (12.1) か、ユーザー提供または削除されたデフォルト コンストラクターのいずれかである場合、オブジェクトはデフォルトで初期化されます。

5.私の意見では、新しい値の初期化の定義は奇妙です。なぜなら、削除されたデフォルト コンストラクターを使用してオブジェクトを作成し、値を初期化できるケースが思いつかないからです。たとえば、 C クラスのint cメンバーをプライベートにすると、C クラスは式の集合体ではなくなります。

C obj1 { };

値の初期化 (以前のような集約の初期化ではない) [#3367, 8.5.4 "List-initialization"] になり、間違いなくコンパイルに失敗します。新しい値の初期化定義で削除されたコンストラクターについて説明していただけますか?

ここには多くのテキストがあることを理解しています。あなたがいくつか答えてくれたら、とても感謝しています。

4

0 に答える 0