【发布时间】:2014-01-18 18:21:20
【问题描述】:
我正在尝试更多地了解 C++,但我对我的编译器所做的事情感到有些困惑。我用 cmets 编写了以下文件,详细说明了发生的情况:
Test getTest()
{
return Test(100, string("testing..."));
}
int main()
{
// These two will call the initializer constructor...
Test t1(5, string("hello"));
Test t2(10, string("goodbye"));
// This will not call operator=. This will call the copy constructor!
Test t3 = t1;
// This will call operator=(Test&)
t3 = t2;
// This will call operator=(Test&&) because rhs is an rvalue
// We will swap the resources in this operator= so that when getTest()
// deletes its resources, it will actually be deleting t3's old resources.
// Likewise, t3 will get getTest()'s resources.
t3 = getTest();
// I don't know what this is doing, but I know it's not calling the destructor.
// I beleive that the memory of t4 is simply what was returned by getTest().
// Likewise with t5.
Test t4(getTest());
Test* t5 = new Test(getTest());
Test t6(t4);
return 0;
}
t4 和 t5 似乎没有进入任何构造函数,实际上只是在使用 getTest() 分配的内存。我假设会发生的是 t4 会进入 rValue 复制构造函数:Test(const Test&& rhs),但即使它的参数是 rValue,它也不会。 Test t4(getTest()) 不调用任何析构函数,这就是为什么我认为 t4 只是获取内存。 t6 确实调用了复制构造函数。
我在 Visual Studio 2013 中查看了汇编代码,发现如下:
Test t4(getTest());
00F59B8C push 8
00F59B8E lea ecx,[t4]
00F59B91 call Test::__autoclassinit2 (0F51285h)
00F59B96 lea eax,[t4]
00F59B99 push eax
00F59B9A call getTest (0F51456h)
00F59B9F add esp,4
00F59BA2 mov byte ptr [ebp-4],8
所以看起来它调用了一个叫做 autoclassinit2 的东西,然后从 getTest 中获取内存,最后将它存储在 t4 中?
所以我想我的问题是:这只是一个编译器优化,直接将内存从 getTest() 中的构造函数提供给 t4?而不是说,1. 在 getTest() 中构造 2. 调用 rVal 复制构造函数 3. 破坏 getTest() 内存?还是这里发生了其他事情?谢谢!
【问题讨论】:
-
哦,原来如此,原来是编译器优化。它通过做一些相同的事情绕过复制构造函数,除了不需要调用析构函数。很酷,但很奇怪,因为我在调试时看不到它!我只是想确保这里没有任何可疑的事情发生,比如它调用了一些我没有想到的默认且可能效率较低的构造函数。非常感谢您的链接。这基本上回答了我的问题
-
请注意,这不是普通的编译器优化:它不是“相同的”。 RVO(以及一般的复制省略)可以改变程序的行为。
-
非常正确,因为它没有在构造函数中调用我的 cout 语句......因为它会在我的 INTENDED 程序中。话虽如此,我想的结构是一样的。也就是说,我可以假设我从构造函数(tempVar)得到的对象是按原样构造的。
-
没错,对象被“就地”构造,避免了复制。
标签: c++ visual-studio c++11