为什么在初始化列表中不需要创建额外的副本就可以对数据进行赋值
Why does data get assigned without an extra copy being created, in an initialization list?
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
}
};
- 如何修复艺术ASCII,我点击一个字母就可以了,但输入一个阶段艺术出来了
- 使用Visual Studio 2012编译时,此代码会给我错误,但是使用代码块就可以了
- 仅捕获异常就可以检测所有二进制文件在C 中读取错误是否足够
- 为什么仅 -fno-signed-0 就可以实现优化,而似乎也需要 -ffinite-math-only (gcc)
- 执行运算符在指针上无需取消就可以使用
- 我应该把Boost.Python的.so文件放在哪里,这样我就可以把它作为一个模块导入,以及我如何将它与Python 2
- 当函数有很多参数和客户端代码只需更改其中时,如何处理情况就可以处理
- 为什么在间接使用基类 typedef 时不断出现语法错误,而直接使用它就可以了?
- Cython代码可以编译成dll吗?这样C++应用程序就可以调用它了
- 仅仅使用(稳定的)第三方库就可以使我的代码无法工作
- 为什么GCC只需将未定义的行为放入循环中就可以允许它
- C++中需要什么,这样我们就可以始终使用引用而从不使用指针
- 将CUDA中的缓冲加倍,这样CPU就可以对持久化内核产生的数据进行操作
- 在Mac OS X上共享一个c++库,这样我就可以在mySQL中添加用户定义的函数
- 将一个char数组传递给函数模板,这样gcc就可以判断出它是一个字面量
- 我如何发送一个unix-exe给我的朋友,这样他就可以通过双击运行它
- 是否有可能钩全局窗口的创建,这样我就可以控制窗口放置在屏幕上的位置
- 如何解除对RenderTarget纹理的绑定,这样它就可以被用作下一个通道的输入
- 为什么在初始化列表中不需要创建额外的副本就可以对数据进行赋值
- 将一个函数声明为transaction_safe就足够了吗?这样它们就可以线程安全地使用了