0

我有以下代码:

    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时没有调用析构函数。这是在 c++ 标准中定义的,还是仅仅是一些仅存在于 VC++ 上的优化?我可以依靠在这种情况下跨平台调用的析构函数吗?getBalls()monkey()

谢谢

4

3 回答 3

2

您遇到了复制省略,这是一种定义明确的机制。不执行不必要的复制取决于实现。

于 2013-03-09T20:21:33.303 回答
2

如果要按值返回复杂结构,避免不必要的构造和破坏的唯一保证方法是使用移动语义。请参阅如何:编写移动构造函数

例如,如果您的类分配内存,则移动构造函数允许您将内存的所有权从一个变量转移到另一个变量。然后优化器将删除传输变量的冗余存储和空检查。

于 2013-03-09T20:26:35.290 回答
1

根据 C++11 标准的第 12.8/31 段:

当满足某些条件时,允许实现省略类对象的复制/移动构造即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被删除的较晚时间。没有优化就被破坏了。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

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

— [...]

这是其中一种情况:

balls getBalls()
{
    balls myBalls;

    return myBalls; <== COVERED BY THE QUOTED PARAGRAPH
//  ^^^^^^^^^^^^^^
}

这是一个真正相关的问题,因为它代表了一般“好像”规则的一个例外。好像”规则基本上允许编译器更改您编写的代码,只要效果相同(“好像”它完全执行您编写的程序)。

但是,在这种情况下,您不能依赖编译器创建临时(或创建临时!),即使您的复制构造函数、移动构造函数或析构函数有副作用。

于 2013-03-09T20:24:45.540 回答