【发布时间】:2011-04-24 14:48:25
【问题描述】:
考虑以下两个类:
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 的第二个构造函数“向上转换”。 现在考虑以下代码:
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 中,返回值优化有效。有两个调用:
- 基数(整数)
- ~Base()
然而,当 main 中需要 Derived 对象时,这里没有什么可取胜的。 “向上转型”需要另一个构造函数/析构函数对。
在案例 2 中,返回值优化不起作用。这里创建和销毁了两个对象:
- Base(int) //创建临时的
- ~Base() //临时销毁
- Base(const Base&) //通过 Derived(const Base&)
- ~Base() //通过~Derived()
现在在我看来,我有三个相互矛盾的要求:
- 我想避免创建临时对象的开销(因为对象创建和销毁在类 Base 中相当昂贵)
- 在 main 中,我需要使用 Derived-object 而不是 Base-object。
显然,这里没有免费的午餐。但我可能错过了一些东西。所以我的问题是:有没有办法结合这些要求?或者有没有人有过类似的经历?
旁注:我知道这样一个事实,即“upcast” Derived(const Base& other) 在运行时可能会失败(这已被处理)。由于代码在语法级别上没问题,我猜这不是编译器避免 RVO 的原因。
【问题讨论】:
-
RVO是指在创建返回值时,通过函数内部的return语句消除“需要”的副本。如果将返回值用作对象的初始化器,则可以将返回值复制到声明的对象中,或者可以消除该副本并直接使用函数的返回值初始化对象。第二个副本不是返回值优化,我认为您指的是这个副本。
-
所以在情况 1 中没有调用
Base的复制 ctor?我不认为这是合法的——b和d1是独立的对象,d1的基类子对象需要从b构造。复制构造函数省略只允许省略临时变量,而不是变量。 [编辑:哦,等等,你的意思是有一个但你没有列出它? “需要另一个 ctor/dtor 对”。我会说 RVO 正在工作,但正如你所见,它并没有达到你想要的效果。]
标签: c++ return-value-optimization