【问题标题】:Construction in c++11c++11中的构造
【发布时间】: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


【解决方案1】:

= 在声明中的意思是“请隐式构造”(基本上)而不是“调用 operator=”。

C++ 有一个称为省略的概念。省略的意思是“使两个或多个变量成为同一件事”。关于编译器何时可以执行此操作有一些规则。与其他优化不同,即使有副作用也是合法的。

如果您使用相同类型的未命名临时变量初始化变量,编译器可以忽略临时变量。如果您从函数返回局部变量,则可以(在某些情况下)将其省略为未命名的返回值。临时人员的未命名返回也是如此。 NRVO 和 RVO 是您想要的关键字。

在许多情况下,如果由于技术原因或编译器限制而导致省略失败,move 会隐式发生。然而明确的move 会阻止省略。因此,了解规则对于前沿优化代码非常重要。

【讨论】:

  • 这进一步讨论了 juanchopanza 所说的内容。非常感谢您的回复,非常感谢
猜你喜欢
  • 2013-01-19
  • 2018-01-23
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 2017-08-05
  • 1970-01-01
  • 2013-09-04
  • 1970-01-01
相关资源
最近更新 更多