c – 当分配给不同类型时,返回值优化是否有效?

考虑以下两个类:

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将提供公共(或可能受保护的)接口来进行实际提取.

点赞