拷贝构造函数和函数返回的临时
我有下面的代码:拷贝构造函数和函数返回的临时
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++上存在的一些优化?在这种情况下,我可以依赖不被调用的析构函数跨平台吗?
感谢
每个段落的C++ 11标准的12.8/31:
当满足特定条件时,的实现允许省略类 对象的复制/移动施工,甚至如果为复制/移动操作选择的构造函数和/或对象 的析构函数具有副作用。在这种情况下,实现将被忽略的复制/移动操作的源和目标视为简单地指向同一对象的两种不同方式,并且销毁该对象 发生在两个对象没有优化就被摧毁了。 复制/移动操作的这个省音,叫做复制省略,允许在下列情况下(其中 可以合并,以消除多个副本):
- 与类返回类型的函数返回语句中,当表达是 非易失性自动对象具有相同cvunqualified 类型作为函数返回类型(不是函数或catch子句参数其他)的名称,复制/移动操作可以通过省略构造 自动对象直接进入函数的返回值
- [...]
这是那些案件之一:
balls getBalls()
{
balls myBalls;
return myBalls; <== COVERED BY THE QUOTED PARAGRAPH
// ^^^^^^^^^^^^^^
}
,这是一个真正相关的一个,因为它代表一个例外一般的“好像”的规则。 “”好像“规则基本上允许编译器更改您编写的代码只要效果相同(”“就好像”它完全执行了您所写的程序)。但是,在这种情况下,即使您的拷贝构造函数,移动构造函数或析构函数有副作用,也不能依赖编译器创建临时文件(或者而不是创建临时文件!)。
你满足复制省略,这是一个定义良好的机制。由执行决定不执行不必要的副本。
有没有这样做的主要编译器?我能否安全地依靠不被主要平台调用的析构函数(比如说windows,osx,linux,android,ps3) – KaiserJohaan 2013-03-09 20:24:00
@KaiserJohaan:不,你不能*依赖这个。这是编译器的选择。实际上,所有编译器都会在大多数情况下执行此操作。但是,你不能假设任何事情。这是“似乎”规则的例外。 – 2013-03-09 20:25:45
@KaiserJohaan:并不是说“析构函数永远不会被调用”。你只有一个比你预期的副本少。当monkey对象被销毁时,仍然会有一个析构函数调用。 – 2013-03-09 20:40:08
如果你想通过值返回一个复杂的结构,唯一可以避免不必要的构造和破坏的方法是使用移动语义。见How to: Write a Move Constructor。
例如,如果您的类分配内存,移动构造函数允许您将内存的所有权从一个变量转移到另一个变量。然后优化器将删除冗余存储并对传输的变量进行空值检查。
'getBalls(){balls myBalls;返回myBalls; }''猴子{球m球; }'...大声笑 – 2013-03-09 20:23:34
更新,开心? :p – KaiserJohaan 2013-03-09 20:24:54
我很高兴与原始版本。任何读“猴子球”的代码都会给我的脸带来微笑。 – 2013-03-09 20:31:11