考虑以下两个类:
class Base
{
Base(const Base& other) {...} // relatively expensive operations here...
Base(int i) {...} // ...here,
virtual ~Base() {...} // ...and here
...
};
class Derived : public Base
{
...
Derived(const Base& other) :Base(other) {...} // some typechecking in here
virtual ~Derived() {}
...
};
这意味着Base可以通过Derived的第二个构造函数“upcast”.
现在考虑以下代码:
Base getBase()
{
int id = ...
return Base(id);
}
...
int main()
{
Base b = getBase(); // CASE 1
Derived d1(b); // "upcast"
Derived d2 = getBase(); // CASE 2
...
}
我正在使用VS2008打开优化(/ Ox / Ob2 / Oi / Ot).我在console-output上检查了对构造函数和析构函数的调用:
在案例1中,返回值优化有效.有两个电话:
> Base(int)
> ~Base()
但是,在main中需要Derived-object时,没有什么可以赢得的. “upcast”需要另一个构造函数/析构函数对.
在案例2中,返回值优化不起作用.这里创建并销毁了两个对象:
> Base(int)//创建临时的
> ~Base()//销毁临时
> Base(const Base&)// via Derived(const Base&)
> ~Base()// via~Endived()
现在在我看来,我有三个相互矛盾的要求:
>我想避免创建临时对象的开销(因为在类Base中对象创建和销毁相当昂贵)
>在main中,我需要一个Derived-object而不是Base-object来使用它.
显然,这里没有免费的午餐.但我可能错过了一些东西.所以我的问题是:有没有办法结合这些要求?或者有没有人有类似的经历?
旁注:我知道这样一个事实,即“upcast”Derived(const Base& other)可能在运行时失败(这已经得到了解决).由于代码在语法层面上是可以的,我猜这不是编译器避免RVO的原因.
最佳答案 这是不好的.
Derived(const Base& other) :Base(other) {...}
其他的静态类型可以属于派生类型.在那种情况下,它将被切片.无论如何,最基本的类都会被复制.
RVO是绕过复制构造函数并就地初始化返回的对象.如果需要派生类型的对象,则必须先构造它. RVO无法为您构建它.
您可能需要考虑不同的方法,而不是派生(const Base& other).这个怎么样:
class Base
{
...
// extract expensive parts of another instance
virtual void initialise(Base& b);
...
};
class Derived : public Base
{
...
Derived(); // cheap constructor
void initialise(Base& b) { /* implementation goes here */ }
...
};
初始化(Base& b)方法将从参数中提取昂贵的部分.它可能具有破坏性. Base将提供公共(或可能受保护的)接口来进行实际提取.