• 第二章构造函数语义学关于NRV优化和copy constructor


    《深度探索C++对象模型》P67最下面说道:

    这个程序的第一个版本不能实施NRV优化,因为test class 缺少一个copy constructor.

    看了一下程序,这个NRV优化和copy constructor木有关系的说啊,所以为什么没有copy constructor就不能进行NRV优化了呢。

    搜了一下,结果很坑爹,就是 侯捷也不知道,Lippman也没有给出答案,而且这个也没有写入C++标准,各个编译器表现不一致。

    记录一下吧。主要参考:

    http://www.newsmth.net/bbsanc.php?path=%2Fgroups%2Fcomp.faq%2FCPlusPlus%2Ftemp1%2FM.1131590829.W0

    http://tieba.baidu.com/p/1056713724

    下面是jjhou的FAQ:
    C++ Object Model 答客问 (3) - NRV 最佳化
    2000.03.25

    leetron wrote (2000/02/11) :

    > 您好,关於深度探索C++物件模型一书,2.3节程式
    > 转化语意学的部分,有个问题
    > 想请教您。
    >
    > 问题:
    > 在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页那种样子的码」。


    侯捷回覆:

    我最害怕的事情就是,读者写信来讨论《深度探索 C++ 物件模型》
    一书内容。因为都是些高手提出些深奥的题目,而我必须把尘封的
    记忆找出来┅ :)

    OK,作者(或译者)没有抱怨的权利 :)。我的回覆如下。

    首先,我要说 leetron 把他的意思描述得非常清楚。在我收到
    的读者来函中,算是上品 — 尤其是描述这麽复杂的思路。

    其次,我同意 leetron 说:

    > 转换成64页的码后,65页与66页分述了两种后续可能出现的
    > 最佳化动作,其中一种即是66页的编译器层面做最佳化。

    但是我不同意 leetron 这样的看法:

    > 如此,虽然66页最佳化后的码看起来并不使用到copy constructor,
    > 但是这些码是根据像64页那种样子的码(注一)最佳化而来的,

    我认为,NRV 最佳化并非是由 p63 的原始码而至 p64 的虚拟码,
    再至 p66 的最佳化。我认为是从 p63 的原始码直接至 p66 的最佳化。
    所以,似乎可以不需要 copy ctor。

    但这麽一来我也无法解释为什麽 lippman 在 p67 最下强调
    「必须要有 copy ctor 才能实施 NRV 最佳化」。

    以下是其他读者的讨论,给您叁考。

    -- quote -- (引自 www.jjhou.com :书籍勘误/深度探索 C++ 物件模型)

    ★黄俊达先生认为: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 无关」的动作。

    ★侯俊杰答覆:颇有道理。但请注意,Lippman
    在 p.205 下方, p.221 上方等处,仍再三强调 copy constructor
    对於 NRV 最佳化的导引之功,不知是否其间有什麽是我们没想到的?


    有查了一下,李普曼原来是给出了答案的了。

    见如下地址: http://book.douban.com/annotation/19292671/

    转过来了:

    书中说,NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系,
    下面一段话摘自网络,参考关于cfront的NRV优化,解释了为什么lippman在书中说有关的原因:
    “早期的 cfront需要一个开关来决定是否应该对代码实行NRV优化,这就是是否有客户(程序员)显式提供的拷贝构造函数:
    如果客户没有显示提供拷贝构造函数,那么cfront认为客户对默认的逐位拷贝语义很满意,由于逐位拷贝本身就是很高效的,
    没必要再对其实施NRV优化;但 如果客户显式提供了拷贝构造函数,这说明客户由于某些原因(例如需要深拷贝等)摆脱了高效的逐位拷贝语义,
    其拷贝动作开销将增大,所以将应对其实施NRV 优化,其结果就是去掉并不必要的拷贝函数调用。
    ”需要说明的一点:NRV优化会导致原本预想中的调用“拷贝构造函数”变成调用别的“构造函数”,
    一旦这个时候,拷贝构造函数和别的构造函数提供的功能不同,就可能会出问题。

    另一个解释如下:
    如果程式没有 explicit copy constructor,编译器会自动为我们做出来(如为 trivial,则直接 bitwise copy;
    如为 nontrivial,则由编译器为我们合成出一个 copy constructor)。
    因此,有没有 explicitcopy constructor 并不影响 NRV 最佳化的实施。NRV 最佳化主要是由编译器 option 来决定要不要实施。

    感觉还是要依靠具体的编译器。。

  • 相关阅读:
    数学思想方法-python计算战(8)-机器视觉-二值化
    04-05组合问题_算法训练
    至HDFS附加内容
    HDU 1010 Tempter of the Bone heuristic 修剪
    二叉树3种遍历的非递归算法
    [Ramda] R.project -- Select a Subset of Properties from a Collection of Objects in Ramda
    [Ramda] Refactor a Promise Chain to Function Composition using Ramda
    [SVG] Combine Multiple SVGs into an SVG Sprite
    [Ramda] Difference between R.converge and R.useWith
    [Ramda] Refactor to a Point Free Function with Ramda's useWith Function
  • 原文地址:https://www.cnblogs.com/cyttina/p/2790076.html
Copyright © 2020-2023  润新知