复制构造函数和返回临时值的函数

Copy constructor and function returning temporaries

本文关键字:函数 构造函数 返回 复制      更新时间:2023-10-16

我有以下一段代码:

    struct balls
    {
        int mNumBalls;
        ~balls();    
    };
    inline balls::~balls()
    {
          // is not called in VS2010 when getBalls returns in monkey constructor
    }
    balls getBalls()
    {
        balls myBalls;
        myBalls.mNumBalls = 5;
        return myBalls;
    }
    struct monkey
    {
        balls mBalls;
        monkey();
    };
    inline monkey::monkey() : mBalls(getBalls())
    {
    }

通过在VS2010调试器中步进,我注意到balls析构函数在monkey()构造函数中返回getBalls()时没有被调用。这是在c++标准中定义的,还是仅仅存在于vc++上的一些优化?在这种情况下,我可以依赖于在跨平台中不调用析构函数吗?

谢谢

您遇到了复制省略,这是一个定义良好的机制。这取决于实现是否执行不必要的复制。

如果您希望按值返回一个复杂的结构,那么唯一保证避免不必要的构造和破坏的方法是使用move语义。参见如何:编写Move构造函数。

例如,如果你的类分配内存,move构造函数允许你将内存的所有权从一个变量转移到另一个变量。然后优化器将删除多余的存储和null检查,

c++ 11标准第12.8/31段:

当满足某些条件时,允许实现省略类的复制/移动构造object,即使为复制/移动操作选择了构造函数和/或对象的析构函数有副作用。在这种情况下,实现处理省略的复制/移动的源和目标操作就是引用同一对象的两种不同方式,以及该对象的销毁发生在时间的后期,如果没有优化,两个对象就会被破坏。复制/移动操作的省略称为复制省略,在以下情况下是允许的(其中可以组合以消除多个副本):

- 在类返回类型函数的返回语句中,当表达式是a的名称时非易失性自动对象(函数或catch子句参数除外)具有相同的cvunqualified类型作为函数返回类型,则可以通过构造省略复制/移动操作将自动对象直接转换为函数的返回值

— [...]

这是其中一种情况:

balls getBalls()
{
    balls myBalls;
    return myBalls; <== COVERED BY THE QUOTED PARAGRAPH
//  ^^^^^^^^^^^^^^
}

,这是一个非常相关的规则,因为它代表了一个异常对于一般的"as if"规则。"as if"规则基本上允许编译器更改您编写的代码,只要效果是相同的("as if"它完全执行您编写的程序)。

但是,在这种情况下,即使复制构造函数、移动构造函数或析构函数有副作用,也不能指望编译器创建临时对象(或者创建临时对象!)。