programing

C ++ 표준에서 허용하는 멤버 변수와 동일한 생성자 인수 이름을 사용하여 멤버 변수를 초기화합니까?

nasanasas 2020. 11. 15. 11:24
반응형

C ++ 표준에서 허용하는 멤버 변수와 동일한 생성자 인수 이름을 사용하여 멤버 변수를 초기화합니까?


아래 예제에 표시된 것과 동일한 이름의 생성자 인수로 멤버 변수를 초기화 할 수 있음을 알아 냈습니다.

#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의 expression-list에있는 이름은 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)
};

initializes X::r to refer to X::a, initializes X::b with the value of the constructor parameter i, initializes X::i with the value of the constructor parameter i, and initializes X::j with the value of X::i; this takes place each time an object of class X is created. ]

[Note: because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. ]

As you can see, there're other interesting thing to note in the above example, and the commentary from the Standard itself.


BTW, as side note, why don't you accept the parameter as const reference:

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

It avoids unneccessary copy of the original vector object.


It is guaranteed always to work (I use it quite often). The compiler knows that the initializer list is of the form: member(value), and so it knows that the first vec in vec(vec) must be a member. Now on the argument to initialize the member, both members, arguments to the constructor and other symbols can be used, as in any expression that would be present inside the constructor. At this point it applies the regular lookup rules, and the argument vec hides the member vec.

Section 12.6.2 of the standard deals with initialization and it explains the process with paragraph 2 dealing with lookup for the member and paragraph 7 with the lookup of the argument.

Names in the expression-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [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) {}
};

One additional counter argument or perhaps just something to be aware of is the situation in which move construction is used to intialize the member variable.

If the member variable needs to be used within the body of the constructor then the member variable needs to be explcitly referenced through the this pointer, otherwise the moved variable will be used which is in an undefined state.

template<typename B>
class A {
public:

  A(B&& b): b(std::forward(b)) {
    this->b.test(); // Correct
    b.test(); // Undefined behavior
  }

private:
  B b;
};

As others have already answered: Yes, this is legal. And yes, this is guaranteed by the Standard to work.

And I find it horrible every time I see it, forcing me to pause: "vec(vec)? WTF? Ah yes, vec is a member variable..."

This is one of the reasons why many, including myself, like to use a naming convention which makes it clear that a member variable is a member variable. Conventions I have seen include adding an underscore suffix (vec_) or an m_ prefix (m_vec). Then, the initializer reads: vec_(vec) / m_vec(vec), which is a no-brainer.

참고URL : https://stackoverflow.com/questions/6185020/initializing-member-variables-using-the-same-name-for-constructor-arguments-as-f

반응형