为什么在初始化列表中不需要创建额外的副本就可以对数据进行赋值



Parashift很好地解释了初始化列表,但没有解释为什么在函数体中赋值之前创建一个变量的额外副本,而在通过初始化列表赋值时不创建额外副本。
我甚至遇到过使用++ I而不是i++的建议,因为前者避免了在赋值之前创建临时I。对于指定在一个医生体内的POD也是一样的吗?在赋值发生之前创建一个临时变量?

换句话说,为什么编译器需要创建一个额外的变量副本?为什么不能直接赋值变量呢?
为什么?

考虑以下内容:

struct C { 
    C() { /* construct the object */ }
};
struct X {
    C member;
    X() { member = C(); }
};

X()构造函数就像你说的:

X() : member() { member = C(); }
首先,调用C构造函数来构造member数据成员。然后执行X的主体,创建第二个临时C对象并将其赋值给member,然后销毁该临时对象。

注意,这只适用于自动初始化的类型。如果member的类型为int或POD类类型(例如),则在输入X构造函数体时将不初始化。

对于这些类型,从性能的角度来看,是在初始化列表中初始化数据成员,还是在构造函数体中赋值给数据成员并不重要;这种差异完全是文体上的。在可能的情况下,为了一致性起见,初始化列表仍应优先使用。

针对你的第一个问题(不涉及"++i" vs "++ +"):

构造函数是一个函数,它有形参。这些形参是作为形参传递的变量的副本(除非使用引用传递)。您现在可以操作这个副本或对它做任何其他事情。然后在进行赋值时,将参数的这个副本(可能已被操纵)赋值给成员变量。当您使用初始化列表时,编译器可以立即优化赋值,而不需要这个副本,因为除了初始化之外,您将不会使用它(并且在将其赋值给成员变量之前不能修改它)。

为什么要在赋值之前创建一个额外的变量副本对象体,但是通过对象赋值时不会创建额外的副本初始化列表。

因为赋值在初始化之后。换句话说,赋值是可选的,但初始化是强制的。你可能不会注意到pod有什么不同。但对于用户定义的数据类型也是如此。

使用++i代替i++

对于pod来说,这并不重要。但是对于用户定义的类,i++确实创建了一个临时副本。所以最好使用++i

struct A {
  A operator ++ (int)  // example of i++
  {
    A temp = *this;
    this->value ++;
    return temp;    // makes 2 copies "temp" and return value
  }
  A& operator ++ ()  // example of ++i
  {
    this->value ++;
    return *this;  // no copy
  }
};

相关内容

  • 没有找到相关文章

最新更新