为什么在初始化列表中分配数据时没有创建额外的副本?

发布于 2024-11-23 15:10:03 字数 335 浏览 3 评论 0原文

Parashift 很好地解释了初始化列表,但没有解释 <强>为什么在构造函数主体中分配之前会创建变量的额外副本,但通过初始化列表分配时不会创建额外的副本。
我什至遇到过使用 ++i 而不是 i++ 的建议,因为前者可以避免在赋值之前创建临时 i 。在 ctor 主体中分配的 POD 是否相同?在赋值之前创建临时变量?

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

Parashift explains initialization lists well, but does not explain why an extra copy of a variable is created before assignment in the ctor body, but no extra copy is created when assigned through an initialization list.
I've even come across advice of using ++i instead of i++ because the former avoids creation of a temporary i before assignment. Is it the same for POD's assigned in a ctor body? A temp variable gets created before the assignment happens?

To put it another way, why does the compiler need to create an extra copy of a variable? Why can't it just assign the variable directly?
Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

吃兔兔 2024-11-30 15:10:03

请考虑以下内容:

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 构造函数的主体为进入。

对于此类类型,从性能角度来看,是在初始化列表中初始化数据成员还是在构造函数主体中分配给数据成员并不重要;差异完全是风格上的。在可能的情况下,为了保持一致性,仍应首选初始化列表。

Consider the following:

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

struct X {
    C member;

    X() { member = C(); }
};

The X() constructor is the same as if you had said:

X() : member() { member = C(); }

First, the C constructor is called to construct the member data member. Then the body of X is executed, a second, temporary C object is created and assigned to member, then the temporary is destroyed.


Note that this is only the case for types that are initialized automatically. If member was of type int or of a POD class type (as examples), it would be uninitalized when the body of the X constructor is entered.

For such types it doesn't really matter from a performance standpoint whether you initialize the data member in the initialization list or assign to the data member in the body of the constructor; the difference is entirely stylistic. Where possible, the initialization list should still be preferred for the sake of consistency.

执着的年纪 2024-11-30 15:10:03

要解决您的第一个问题,特别是关于副本的问题(不涉及“++i”与“i++”):

构造函数是一个函数,并且它有参数。这些参数是作为参数传递的变量的副本(除非使用通过引用传递)。您现在可以操纵此副本或用它执行任何其他操作。然后,当您分配时,您将获取该参数的副本(可操作的可能性)并将其分配给成员变量。当您使用初始化列表时,编译器可以在没有此副本的情况下立即优化赋值,因为除了初始化之外,您不会将其用于任何其他用途(并且在将其分配给成员变量之前无法对其进行修改)。

To address your first question specifically regarding the copy (without touching on "++i" vs "i++"):

The constructor is a function, and it has parameters. These parameters are copies of the variables passed as parameters (unless passing by reference is used). You can now manipulate this copy or do anything else with it. Then when you assign, you take this copy of the parameter (possibility manipulated) and assign it to the member variable. When you use an initialization list, the compiler can optimize the assignment immediately without this copy, as you will not be using it for anything but the initialization (and cannot modify it before assigning it to the member variable).

世界和平 2024-11-30 15:10:03

为什么在赋值之前会创建变量的额外副本
ctor 主体,但通过分配时不会创建额外的副本
初始化列表。

因为赋值是在初始化之后进行的。换句话说,赋值是可选的,但初始化是强制性的。您可能不会注意到 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
  }
};

why an extra copy of a variable is created before assignment in the
ctor body, but no extra copy is created when assigned through an
initialization list.

Because assignment follows initialization. In other words, assignment is optional, but initialization is mandatory. You may not notice much difference for PODs. But the same holds true for user defined data types.

advice of using ++i instead of i++

Again for PODs it doesn't matter much. But for user defined classes, i++ does create a temporary copy. So it's better to use ++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
  }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文