繁体   English   中英

分配给其他类型时,返回值优化是否起作用?

[英]Does return value optimization work, when assigning to a different type?

请考虑以下两类:

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() {}
  ...
};

这意味着可以通过Derived的第二个构造函数来“转换” Base 现在考虑以下代码:

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)。 我在控制台输出上检查了对构造函数和析构函数的调用:

情况1中,返回值优化有效。 有两个电话:

  1. 基数(整数)
  2. 〜基础()

但是,当main中需要派生对象时,这里没有什么可赢得的。 “ upcast”需要另一个构造器/析构器对。

情况2中,返回值优化无效。 在此创建并销毁了两个对象:

  1. Base(int) //创建临时
  2. 〜Base() //销毁临时对象
  3. Base(const Base&) //通过派生(const Base&)
  4. 〜Base() //通过〜Derived()

现在在我看来,我有三个相互矛盾的要求:

  1. 我想避免创建临时对象的开销(因为在Base类中创建和销毁对象非常昂贵)
  2. main中 ,我需要使用Derived对象而不是Base对象

显然,这里没有免费的午餐。 但是我可能已经错过了一些东西。 所以我的问题是:有没有办法组合这些要求? 还是有人有过类似的经历?

旁注:我知道一个事实,即在运行时,“ upcast”派生的(const Base等)可能会失败(已解决)。 由于代码在语法级别上是可以的,所以我想这不是编译器避免使用RVO的原因。

这不好。

Derived(const Base& other)   :Base(other) {...}

other的静态类型可以属于派生类型。 在这种情况下,它将被切成薄片。 无论如何,将在该基类的顶部进行复制。

RVO是关于绕过复制构造函数并就地初始化返回的对象。 如果需要派生类型的对象,则必须首先构造它。 RVO无法为您构建它。

您可能需要考虑其他方法,而不是Derived(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 */  }
  ...
};

initialise(Base& b)方法将从参数中提取昂贵的部分。 它可能具有破坏性。 Base将提供公共(或受保护的)接口来进行实际提取。

如何向Derived添加构造函数?

Derived(Base (*f)(void)) : Base(f()) { ... }

然后Derived d3 = getBase; 可能会为您带来所需的优化。 由于我不得不在Derived指定f的空参数列表,因此可能不是很实际。 但是,使其成为模板构造函数,就可以使用用户编写的函子,它是boost:bind或C ++ 0x lambda的结果(如果有)。

如果做不到这一点,提取id = ...的一部分getBase成一个函数getId ,并给予Derived构造服用int该传递id到它的Base子对象。 但是,毫无疑问,实际代码比这要复杂得多,这可能会导致拖出很多有关该地点的参数。 也许是轻量级的BaseParameters类,您可以使用它代替Base直到实际需要完成缓慢工作的位置,然后将转换为BaseDerived或其他相关类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM