使用与构造函数参数相同的名称初始化成员变量,以及C++标准允许的成员变量?

Nil*_*ils 67 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;
}
Run Code Online (Sandbox Code Playgroud)

带有参数的g ++ 4.4 -Wall -Wextra -pedantic没有提供任何警告并且工作正常.它也适用于clang ++.我想知道C++标准对此有何看法?是否合法并保证始终有效?

Naw*_*waz 83

我想知道C++标准对此有何看法?是否合法并保证始终有效?

是.这完全合法.完全符合标准.

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

既然你在标准中要求参考,那么它就是一个例子.

§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)
};
Run Code Online (Sandbox Code Playgroud)

初始化X :: r以引用X :: a,使用构造函数参数i的值初始化X :: b,使用构造函数参数i的值初始化X :: i,并使用值初始化X :: j X :: i; 每次创建类X的对象时都会发生这种情况.]

[注意:因为mem-initializer是在构造函数的范围内计算的,所以this指针可以在mem-initializer的表达式列表中用于引用正在初始化的对象.]

正如您所看到的,在上面的示例中还有其他有趣的事情需要注意,以及标准本身的注释.


BTW,作为旁注,为什么不接受参数作为const引用:

 Blah(const std::vector<int> & vec): vec(vec) {}
      ^^^^const              ^reference
Run Code Online (Sandbox Code Playgroud)

它避免了原始矢量对象的不必要副本.

  • 在C++ 0x中,最好接受它的值,然后将其移动到目的地:`Blah(std :: vector <int> vec):vec(std :: move(vec)){}`.您可以在C++ 03中模拟这样:`Blah(std :: vector <int> vecSrc){std :: swap(vec,vecSrc); }`. (3认同)
  • @Tomalak:大声笑,我仍然惊讶你发现那是不可读的.这是非常简单的,我认为,它很常见. (2认同)
  • 虽然这是合法的,但这是不好的做法。当使用 -Wshadow(或等效的)时,它会使水变得浑浊,并使您面临更有害的编程错误。 (2认同)

Dav*_*eas 13

保证始终工作(我经常使用它).编译器知道初始化列表的形式为:member(value),因此它知道第一vecvec(vec)必须是成员.现在,在初始化成员的参数上,可以使用构造函数的参数和其他符号,就像在构造函数中存在的任何表达式一样.此时它应用常规查找规则,并且参数vec隐藏该成员vec.

该标准的第12.6.2节涉及初始化,它解释了第2段处理成员查找和第7段查询参数的过程.

mem-initializer的表达式列表中的名称在为其指定mem-initializer的构造函数的范围内进行计算.[例:

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) {}
};
Run Code Online (Sandbox Code Playgroud)

  • +1 这里的关键点,其他人都没有说:这是有效的,因为应用了与 ctor 主体中使用的相同的查找规则,*which* - 这是关键点 - 意味着参数隐藏/隐藏成员,这就是为什么这样做(对于“工作”这个词的某些定义;恕我直言,任何隐藏/阴影都是糟糕的风格)。 (2认同)