1

更新: 技術的には、各メンバーの後に' = 0' または ' 'を追加するのを忘れる可能性があるため、クラス全体を一度にゼロ初期化する方法があるかどうかを確認しています。{}コメントの 1 つは、明示的にデフォルト設定された引数なしの c-tor は、フォームの値の初期化中にゼロ初期化を有効にするMyClass c{};ことを述べています。http://en.cppreference.com/w/cpp/language/value_initializationを見ると、どのステートメントがこれを指定しているかわかりません。

C++11 ではさまざまな初期化構造の意味と構文が変更されたため、初期化は現在複雑なトピックです。他の質問から十分な情報を収集できませんでした。ただし、たとえば、デフォルトのコンストラクターを書くとゼロ初期化が強制されますか?を参照してください。.

私が直面している具体的な問題は次のとおりです。(1) デフォルトの c-tor を宣言するクラスと、(2) そうでないクラスの両方で、自分のクラスのメンバーが確実にゼロになるようにしたいのです。

(2){}の場合、値の初期化の構文であり、ゼロ初期化に変換されるか、クラスが集合体の場合は集合体の初期化に変換されるため、初期化はジョブを実行します-初期化子が提供されなかったメンバーの場合(すべて! ) はゼロで初期化されます。

しかし、(1)については、何が最善のアプローチになるのかまだわかりません。私が収集したすべての情報から、デフォルトのc-torを提供する場合(たとえば、メンバーの一部をいくつかの値に設定する場合)、残りのメンバーを明示的にゼロにする必要があることを学びました。そうしないと、構文MyClass c = MyClass();またはC ++ 11MyClass c{};機能しません. 言い換えれば、この場合の値の初期化は、単に c-tor を呼び出すことを意味し、それだけです (ゼロ化はありません)。

値を取り、それらの値をメンバーのサブセットに設定するc-torを宣言すると、同じ状況に遭遇しますが、他のメンバーをゼロに設定したい場合:それを行うための省略形はありません-I 3つのオプションについて考えています:

class MyClass
{
  int a;
  int b;
  int c;

  MyClass(int a)
  {
    this->a = a;
    // now b and c have indeterminate values, what to do? (before setting 'a')


    // option #1
    *this = MyClass{}; // we lost the ability to do this since it requires default c-tor which is inhibited by declaring this c-tor; even if we declare one (private), it needs to explicitly zero members one-by-one

    // option #2
    std::memset(this, 0, sizeof(*this)); // ugly C call, only works for PODs (which require, among other things, a default c-tor defaulted on first declaration)

    // option #3
    // don't declare this c-tor, but instead use the "named constructor idiom"/factory below
  }


  static MyClass create(int a)
  {
    MyClass obj{}; // will zero-initialize since there are no c-tors
    obj.a = a;
    return obj;
  }
};

私の推論は正しいですか?3つの選択肢のうちどれを選びますか?

4

3 に答える 3

4

クラス内初期化の使用についてはどうですか?

class Foo
{
    int _a{}; // zero-it
    int _b{}; // zero-it
public:
    Foo(int a): _a(a){} // over-rules the default in-class initialization
};
于 2015-04-02T12:44:28.190 に答える
3

オプション 4 および 5:

オプション 4:


MyClass(int a) :a(a), b(0), c(0)
  {
  }

オプション 5:


class MyClass
  {
      int a = 0;
      int b = 0;
      int c = 0;

      MyClass(int a) : a(a) {
      }
  }
于 2015-04-02T12:46:17.273 に答える
1

私の謙虚な意見では、ゼロ初期化を確実にする最も簡単な方法は、抽象化のレイヤーを追加することです。

class MyClass
{
    struct
    {
        int a;
        int b;
        int c;
    } data{};
public:
    MyClass(int a) : data{a} {}
};

データ メンバーを構造体に移動すると、値の初期化を使用してゼロ初期化を実行できます。もちろん、これらのデータ メンバーにアクセスするのは少しdata.a面倒aですMyClass。のデフォルト コンストラクターは、 のブレース初期化子により、 とそのすべてのメンバーMyClassのゼロ初期化を実行します。さらに、 のコンストラクターで集計初期化を使用できます。これにより、明示的に初期化されていないデータ メンバーも値初期化​​されます。datadataMyClass

データ メンバーの間接アクセスの欠点は、集約の代わりに継承を使用することで克服できます。

struct my_data
{
    int a;
    int b;
    int c;
};

class MyClass : private my_data
{
    MyClass() : my_data() {}
public:
    MyClass(int a) : MyClass() { this->a = a; }
};

base-initializer を明示的に指定するとmy_data()、値の初期化も呼び出され、ゼロ初期化につながります。constexprこのデフォルト コンストラクターは、おそらくおよびとしてマークする必要がありnoexceptます。もはや些細なことではないことに注意してください。集約初期化または転送コンストラクターを使用して、割り当ての代わりに初期化を使用できます。

class MyClass : private my_data
{
public:
    MyClass(int a) : my_data{a} {}
};

ゼロ初期化を保証するラッパー テンプレートを作成することもできますが、この場合の利点は議論の余地があります。

template<typename T>
struct zero_init_helper : public T
{
    zero_init_helper() : T() {}
};

struct my_data
{
    int a;
    int b;
    int c;
};

class MyClass : private zero_init_helper<my_data>
{
public:
    MyClass(int a) { this->a = a; }
};

ユーザー提供のコンストラクターを持つことzero_init_helperは、もはや集合体ではないため、集合体の初期化を使用できなくなりました。の ctor で割り当ての代わりに初期化を使用するにはMyClass、転送コンストラクターを追加する必要があります。

template<typename T>
struct zero_init_helper : public T
{
    zero_init_helper() : T() {}

    template<typename... Args>
    zero_init_helper(Args&&... args) : T{std::forward<Args>(args)...} {}
};

class MyClass : private zero_init_helper<my_data>
{
public:
    MyClass(int a) : zero_init_helper(a) {}
};

コンストラクター テンプレートを制約するis_brace_constructibleには、現在の C++ 標準の一部ではない何らかの特性が必要です。しかし、これはすでに、問題に対するとてつもなく複雑な解決策です。


オプション #1 を次のように実装することもできます。

class MyClass
{
  int a;
  int b;
  int c;

  MyClass() = default; // or public, if you like

public:
  MyClass(int a)
  {
    *this = MyClass{}; // the explicitly defaulted default ctor
                       // makes value-init use zero-init
    this->a = a;
  }
};

コンストラクターの委任はどうですか?

class MyClass
{
  int a;
  int b;
  int c;

  MyClass() = default; // or public, if you like

public:
  MyClass(int a) : MyClass() // ctor delegation
  {
      this->a = a;
  }
};

[class.base.init]/7 は、上記の例が値の初期化を呼び出すことを示唆しています。これは、クラスにはユーザー提供のデフォルト コンストラクター [dcl.init]/8.2がないため、ゼロ初期化につながります。最近のバージョンの clang++ はオブジェクトをゼロで初期化するように見えますが、最近のバージョンの g++ はそうではありません。これをg++ バグ #65816として報告しました。

于 2015-04-14T15:56:58.270 に答える