考虑以下最简单的例子:
struct A
{
int a;
};
A a; //1
A b = A(); //2
int main(){ }
//1
和//2
之间的区别是什么,除非1由普通的默认ctor进行,而2由琐碎的复制者执行。我对内存布局很感兴趣,那些情况会有所不同吗?
答案 0 :(得分:2)
如果这两个构造函数和析构函数都是微不足道的,那么两者都等同于"就像"规则。 (虽然,如果它们是局部变量,则会有区别:第二个指定值初始化为零而不是默认初始化为不确定值。)
如果它们是非平凡的,那么如果编译器应用了复制省略,则两者都是等价的 - 这是一种情况,从临时初始化对象,允许进行优化。
在任何情况下,变量的内存布局都是相同的。如果副本没有被删除,//2
将创建,初始化,复制和销毁临时文件。
答案 1 :(得分:2)
默认情况下的初始化和复制ctors完全相同吗?
否强>
语言以不同方式定义这些类型的初始化。但是,在您的特定示例中,以单个副本构造为模,结果语义是相同的。
我对内存布局感兴趣,这些情况会有所不同吗?
否强>
内存布局必须独立于初始化方法,否则一个翻译单元中定义的函数无法理解另一个翻译单元中定义的任何对象。
程序中的每个T
都具有相同的内存布局。实际上,每个编译器遵循与您相同的ABI生成的T
将具有相同的内存布局。
这是非常慎重的。
答案 2 :(得分:1)
我的系统上它们是相同的:
struct A
{
int a;
A() { a = 7;}
};
int main(){
A a; //1
A b = A(); //2
}
给出
310 A a; //1
00401b49: lea 0xc(%esp),%eax
00401b4d: mov %eax,%ecx
00401b4f: call 0x403cd8 <A::A()>
312 A b = A(); //2
00401b54: lea 0x8(%esp),%eax
00401b58: mov %eax,%ecx
00401b5a: call 0x403cd8 <A::A()>