我有以下代码:
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 :(得分:2)
您正在与 copy elision 会面,这是一种定义明确的机制。不执行不必要的副本取决于实现。
答案 1 :(得分:2)
如果要按值返回复杂结构,避免不必要的构造和破坏的唯一保证方法是使用移动语义。请参阅How to: Write a Move Constructor。
例如,如果您的类分配内存,则移动构造函数允许您将内存的所有权从一个变量转移到另一个变量。然后,优化器将删除冗余存储并对传输的变量进行空检查。
答案 2 :(得分:1)
根据C ++ 11标准的第12.8 / 31段:
当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择的构造函数和/或对象的析构函数也是如此 有副作用。在这种情况下,实现处理省略的复制/移动的源和目标 操作只是指向同一对象的两种不同方式,以及对该对象的破坏 发生在两个对象在没有优化的情况下被销毁的时间的晚些时候。 在以下情况下允许复制/移动操作的省略,称为复制省略(其中 可以合并以消除多个副本):
- 在具有类返回类型的函数的return语句中,当表达式是a的名称时 非易失性自动对象(函数或catch子句参数除外)具有相同的cvunqualified 键入函数返回类型,构造可以省略复制/移动操作 自动对象直接进入函数的返回值
- [...]
这是其中一种情况:
balls getBalls()
{
balls myBalls;
return myBalls; <== COVERED BY THE QUOTED PARAGRAPH
// ^^^^^^^^^^^^^^
}
并且它是一个非常相关的,因为它代表了一般“好像”规则的异常。 “好像”规则基本上允许编译器更改您编写的代码,只要效果相同(“就好像”它完全执行你写的程序)。
但是,在这种情况下,您不能依赖编译器创建临时(或不创建临时!),即使您的复制构造函数,移动构造函数或析构函数有副作用。 / p>