2013-03-09 97 views
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析构函数不是调用时getBalls()回报在monkey()构造。这是在C++标准中定义还是仅仅在VC++上存在的一些优化?在这种情况下,我可以依赖不被调用的析构函数跨平台吗?

感谢

+0

'getBalls(){balls myBalls;返回myBalls; }''猴子{球m球; }'...大声笑 – 2013-03-09 20:23:34

+0

更新,开心? :p – KaiserJohaan 2013-03-09 20:24:54

+0

我很高兴与原始版本。任何读“猴子球”的代码都会给我的脸带来微笑。 – 2013-03-09 20:31:11

回答

1

每个段落的C++ 11标准的12.8/31:

当满足特定条件时,的实现允许省略类 对象的复制/移动施工甚至如果为复制/移动操作选择的构造函数和/或对象 的析构函数具有副作用。在这种情况下,实现将被忽略的复制/移动操作的源和目标视为简单地指向同一对象的两种不同方式,并且销毁该对象 发生在两个对象没有优化就被摧毁了。 复制/移动操作的这个省音,叫做复制省略,允许在下列情况下(其中 可以合并,以消除多个副本):

- 与类返回类型的函数返回语句中,当表达是 非易失性自动对象具有相同cvunqualified 类型作为函数返回类型(不是函数或catch子句参数其他)的名称,复制/移动操作可以通过省略构造 自动对象直接进入函数的返回值

- [...]

这是那些案件之一:

balls getBalls() 
{ 
    balls myBalls; 

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

,这是一个真正相关的一个,因为它代表一个例外一般的“好像”的规则。 “”好像“规则基本上允许编译器更改您编写的代码只要效果相同(”“就好像”它完全执行了您所写的程序)。但是,在这种情况下,即使您的拷贝构造函数,移动构造函数或析构函数有副作用,也不能依赖编译器创建临时文件(或者而不是创建临时文件!)。

2

你满足复制省略,这是一个定义良好的机制。由执行决定不执行不必要的副本。

+0

有没有这样做的主要编译器?我能否安全地依靠不被主要平台调用的析构函数(比如说windows,osx,linux,android,ps3) – KaiserJohaan 2013-03-09 20:24:00

+0

@KaiserJohaan:不,你不能*依赖这个。这是编译器的选择。实际上,所有编译器都会在大多数情况下执行此操作。但是,你不能假设任何事情。这是“似乎”规则的例外。 – 2013-03-09 20:25:45

+0

@KaiserJohaan:并不是说“析构函数永远不会被调用”。你只有一个比你预期的副本少。当monkey对象被销毁时,仍然会有一个析构函数调用。 – 2013-03-09 20:40:08

2

如果你想通过值返回一个复杂的结构,唯一可以避免不必要的构造和破坏的方法是使用移动语义。见How to: Write a Move Constructor

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