2014-01-18 45 views
2

我想了解更多关于C++的知识,我对编译器的工作感到困惑。我写了下面的文件,详细的意见发生了什么:C++中的构造11

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拷贝构造函数:测试(const测试& & rhs),但它甚至没有它的参数是一个rValue。测试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()内存?还是有其他事情在这里?谢谢!

+0

看看[*返回值优化*](http://en.wikipedia.org/wiki/Return_value_optimization)。 – juanchopanza

+0

哦,我明白了,所以这是一个编译器优化。它通过做一些相同的东西来绕过拷贝构造器,除了不需要调用析构函数。很酷,但很奇怪,因为我在调试时看不到它!我只是想确保这里没有鱼腥味,就像它调用了一些我没有想到的默认和效率较低的构造函数。非常感谢这个链接。这基本上回答了我的问题 – user2045279

+0

请注意,这不是普通的编译器优化:它不是“相同的”。允许RVO(和一般的复制elision)改变程序的行为。 – juanchopanza

回答

3

=在一个声明中意味着'隐式构造请求'(基本上)而不是'调用操作符='。

C++有一个被称为elision的概念。 Elision意味着'使两个或更多变量成为同一个事物'。有关于编译器何时可以执行的规则。与其他优化不同,即使存在副作用也是合法的。

如果使用相同类型的未命名临时变量初始化变量,编译器可以暂时取消该临时变量。如果你从一个函数返回一个局部变量,它可以(在某些情况下)被忽略为未命名的返回值。同上,用于临时匿名回报。 NRVO和RVO是您想要的关键字。

在很多情况下,如果elision由于技术原因或编译器限制而失败,则隐式发生move。但明确的move块elision。因此了解这些规则对于出血边缘优化代码很重要。

+0

这进一步讨论了juanchopanza正在谈论的内容。我很欣赏这个答复,非常感谢 – user2045279