• 全部
  • 问答

讨论《C++ Object Model 》一书中的NRV问题!。P66页 實施NRV最佳化 的问题。

Kingore 2004-04-22 05:20:26
因为抽空重新翻了一下,发现问题:

在67頁,最下面兩行:
> 這個程式的第一個版本不能實施NRV最佳化,因為test class
> 缺少一個copy constructor。
> 但是在66頁「在編譯器層面做最佳化」那一段中所列的碼顯示,
> 當編譯器把xx以__result取代,變成__result.X::X();
> 即default constructor被喚起。喚起default constructor
> 是可以理解的,可是編譯器轉換後的碼並沒有使用到
> copy constructor呀,為什麼67頁最後兩行卻說缺少一個
> copy constructor,就不能實施這個最佳化了呢?


观点讨论[解释+ 猜想]:
我的解釋是:
> 如同63頁與64頁「回返值的初始化」這一段,編譯器可能將
> 63頁下面的 X bar()函式定義轉換成64頁的虛擬碼,其中有
> 一行__result.X::X(xx); 這會使用到copy constructor。
>
> 轉換成64頁的碼後,65頁與66頁分述了兩種後續可能出現的
> 最佳化動作,其中一種即是66頁的編譯器層面做最佳化。
> 如此,雖然66頁最佳化後的碼看起來並不使用到copy constructor,
> 但是這些碼是根據像64頁那種樣子的碼(註一)最佳化而來的,
> 而若沒有copy constructor,根本無法轉換成64頁那種虛擬碼,
> 因為其中有一個呼叫copy constructor的動作。所以,雖然
> 66頁經過編譯器最佳化的結果省去了__result.X::X(xx);
> 這個copy constructor的呼喚動作(因為根本沒有xx了),
> 但若沒有明白提供一個copy constructor,卻無法讓編譯器
> 進行這樣的最佳化。
>
> 另一方面,我參考第5章,205頁最下面一段話:
> 「一般而言如果你的設計之中,有許多函式都需要以傳值(by value)
> 傳回一個local class object....那麼提供一個copy constructor
> 就比較合理--甚至即使default memberwise語意已經足夠。
> 它的出現會觸發NRV最佳化。然而,就像我在前一個例子中
> 所展現的那樣,NRV最佳化後將不再需要喚起copy constructor,
> 因為運算結果已經被直接計算於「將被傳回的object」體內了。」
> 所以,我提出如上所述那個解釋,但不確定是否正確,所
> 以e-mail給您以確認一下。
>
> 註一:當然,編譯器到底怎麼實作這些轉換動作,理論上
> 我們是未知的,不能一概而論。所以我寫「像64頁那種樣子的碼」。

2。Lippman 在 p67 最後一行所言『这个程式的第一个版本
不能实施 NRV 最佳化,因为 test class 缺少一个 copy constructor』,此语错误。
黄先生认为如果程式没有 explicit copy constructor,编译器会
自动为我们做出来(如为 trivial,则直接 bitwise copy;如为 nontrivial,
则由编译器为我们合成出一个 copy constructor)。因此,有没有 explicit
copy constructor 并不影响 NRV 最佳化的实施。他认为 NRV 最佳化主要是
由编译器 option 来决定要不要实施。他并且做了一些实验,判断 VC 和 gcc
都没有做到 NRV 最佳化,而其不做的理由不是因为技术上的困难,是为了
避免造成「user defined copy constructor 之副作用失效」-- 所谓副作用
是指,例如「在 user defined copy constructor 中做一个 cout 输出」之类
这种「与 memberwise copy 无关」的动作。

希望大家踊跃讨论!·!!


...全文
34 点赞 收藏 14
写回复
14 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
xuwedo2003 2004-05-13
http://expert.csdn.net/Expert/topic/3022/3022043.xml?temp=.6397364
回复
Kingore 2004-04-23
就是,呵呵,我标题写错了:(

附带讨论以下问题:
中文版的P70页:
以下内容:
Although the NRV optimization provides significant performance improvement, there are several criticisms of this approach. One is that because the optimization is done silently by the compiler, whether it was actually performed is not always clear (particularly since few compilers document the extent of its implementation or whether it is implemented at all). A second is that as the function becomes more complicated, the optimization becomes more difficult to apply. In cfront, for example, the optimization is applied only if all the named return statements occur at the top level of the function. Introduce a nested local block with a return statement, and cfront quietly turns off the optimization. Programmers arguing this case recommend the specialized constructor strategy instead.

These two criticisms concern the compiler's possibly failing to apply the optimization.

//以上是NRV受批评的两个原因,容易懂,
//下面的第三个原因:提及到的程序说破坏对称性,并且说“In this case, the symmetry is broken by the optimization, and the program, albeit faster, fails.”
---》对称性被NRV优化破坏,虽然快了,但是错误的?》》
我的问题是:对称性怎么被破坏了?
程序又怎么错误了?

A third criticism takes the opposite position: Some programmers actually criticize the application of the optimization. Can you see what their complaint might be? For example, imagine you had instrumented your copy constructor such that your application depended on the symmetry of its invocation for each destructor invoked on an object initialized by copying; for example,

void foo()

{

// copy constructor expected here

X xx = bar();

// ...

// destructor invoked here

}

In this case, the symmetry is broken by the optimization, and the program, albeit faster, fails. Is the compiler at fault here for suppressing the copy constructor invocation? That is, must the copy constructor be invoked in every program situation in which the initialization of an object is achieved through copying?

大家踊跃讨论!:)

回复
liujiewen 2004-04-23
问一个不相关的问题:
楼上讨论的《C++ Object Model》是不是就是《Inside The C++ Object Model》,中文翻译为《深入探索C++对象模型》这本书?谢谢!
回复
Kingore 2004-04-23
?,是指针或者普通类型或者可以,
是复杂的对象呢?
这样不太可能吧?
回复
icenl 2004-04-23
这本书的英文版,由于我英文太差看起来很吃力; 可悲的是中文版看起来更吃力——本人能力有限不能参与讨论了
回复
BluntBlade 2004-04-22
谁能保证编译器不做如下的BT转换呢:
X bar( )
{
}
====>
void bar(X& __result)
{
__result.X::X(0);
}

呵呵。只有编译器的作者才知道了。
回复
Kingore 2004-04-22
angelo23(angelo) 的意思值得大家考虑一下,我觉得可能LIPPMAN也是这个意思,

回复
Kingore 2004-04-22
同理,你没有在bar()写任何语句,当然返回结果就是
X bar( )
{
}
====>
void bar(X& __result)
{
__result.X::X();

}


这里应该没有调用copy constructor吧?!因而也不需要copy constructor
但这里也做了NRV优化?!

回复
BluntBlade 2004-04-22
如果没有涉及对象切割或者是内存分配(深拷贝或者浅拷贝),那么使用bitwise copy语义就足够了的。
回复
BluntBlade 2004-04-22
同理,你没有在bar()写任何语句,当然返回结果就是
X bar( )
{
}
====>
void bar(X& __result)
{
__result.X::X();

}
罗。如果你这样写
X bar()
{
return (1 + 2);
}
那么====>
void bar(X& __result)
{
__result.X::X(3);

}
而对于
X x = bar();
来说,就是
X x; // 伪码,此处只分配内存
bar(x); // 只构造,不返回对象。
回复
angelo23 2004-04-22
看到后面他说copy constructor是可以用来trigger(好像是用的这个词)NRV Optimization的。上次我问的NRV的问题,BluntBlade和Jinhao的解答,我觉得按Lippman的意思是,一般来说用户提供的copy constructor会因为函数调用和用户代码的不够高效,而造成程序效率的下降,这时候进行NRV优化可以带来效率的提高;但是如果用户没有提供自定义的copy constructor,那么编译器为其生成的(甚至只是概念上生成,实际只是作bitwise copy)的代码的效率应该就足够了,不需要再做优化了。
回复
BluntBlade 2004-04-22
什么叫“没有源对象”?
int A::getVal()
{
return _Val;
}
然后
A a;
a.getVal();
你看出来这里有源对象了么?
源代码里没有,但是对编译器而言实际上是
int A::getVal(A * const this)
{
return this->_Val;
}

A a;
a.getVal(&a);

嘿嘿,NRV优化是编译器实现的,你认为它会不会往里面偷偷地塞东西?


回复
Kingore 2004-04-22
X bar( )
{
}
====>
void bar(X& __result)
{
__result.X::X();

}

如果这里印错了?
调用的是copy ctor的话,
从哪里COPY呢?
源对象都没有!!!
回复
BluntBlade 2004-04-22
我个人认为是下面这句
__result.X::X();
印错了。
编译器的确是调用了copy ctor的。
前提是返回语句这样写
return CLASSA(/* 这里写一个能够返回与CLASSA的ctor的参数类型匹配的值的表达式 */);
回复
发帖
C++ 语言
创建于2007-09-28

5.9w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
申请成为版主
帖子事件
创建了帖子
2004-04-22 05:20
社区公告
暂无公告