1. ホーム
  2. c++

[解決済み] C++規格で認められているメンバ変数と同じ名前をコンストラクタの引数に使ってメンバ変数を初期化すること?重複

2023-05-12 19:58:44

質問

以下の例のように、同名のコンストラクタ引数でメンバ変数を初期化することが可能であることがわかりました。

#include <cstdio>
#include <vector>

class Blah {
    std::vector<int> vec;

public:
    Blah(std::vector<int> vec): vec(vec)
    {}

    void printVec() {

        for(unsigned int i=0; i<vec.size(); i++)
            printf("%i ", vec.at(i));

        printf("\n");
    }
};

int main() {

    std::vector<int> myVector(3);

    myVector.at(0) = 1;
    myVector.at(1) = 2;
    myVector.at(2) = 3;

    Blah blah(myVector);

    blah.printVec();

    return 0;
}

g++ 4.4 を引数として -Wall -Wextra -pedantic は警告を出さず、正しく動作します。clang++でも動きます。C++の標準ではどうなっているのでしょうか?これは合法で、常に動作することが保証されているのでしょうか?

どのように解決するのですか?

<ブロッククオート

C++の標準ではどうなっているんだろう?合法で、常に動作することが保証されているのでしょうか?

はい、それは完全に合法です。完全に標準に適合しています。

Blah(std::vector<int> vec): vec(vec){}
                             ^   ^                           
                             |   |
                             |    this is the argument to the constructor
                             this is your member data

規格の参照を求められたので、ここに例とともに掲載します。

§12.6.2/7

mem-initializerの式リスト内の名前は、mem-initializerが指定されたコンストラクタのスコープで評価されます。

[Example:
class X {
 int a;
 int b;
 int i;
 int j;
 public:
 const int& r;
  X(int i): r(a), b(i), i(i), j(this->i) {}
                      //^^^^ note this (added by Nawaz)
};

<ブロッククオート

はX::aを参照するようにX::rを初期化します。 X::bをコンストラクタのパラメータiの値で初期化します. を初期化し、X::bをコンストラクタ・パラメータiの値で初期化します。 X::i をコンストラクタのパラメータ i の値で初期化し、X::j をコンストラクタのパラメータ i の値で初期化します。 を初期化し、X::j を X::i の値で初期化する。 をX::iの値で初期化します。 これはクラスXのオブジェクトが生成されるたびに行われます。 これはクラスXのオブジェクトが生成されるたびに行われます。]

[注意: なぜなら mem-initializerはコンストラクタのスコープで評価されるため のスコープで評価されるので、この ポインタを使用することができます。 の式リストで使用することができます。 の式リストで、初期化されるオブジェクトを参照するために 初期化されるオブジェクトを参照することができます。]

ご覧の通り、上記の例やStandard自体の解説には、他にも興味深い点があります。


ところで、余談ですが、なぜパラメータを const として受け取ってはどうでしょうか。

 Blah(const std::vector<int> & vec): vec(vec) {}
      ^^^^const              ^reference

元のベクトルオブジェクトの不必要なコピーを避けることができます。