精华内容
下载资源
问答
  • NRV优化

    2021-03-18 11:03:07
    转载自:关于NRV优化
    展开全文
  • nrv优化

    2014-06-30 14:17:30
    原文地址 ... 大纲: ... 函数返回局部对象的拷贝的一般实现方式。... NRV优化触发的疑问。 一、函数返回局部对象的拷贝的一般实现方式 比如有这么一段函数定义: [cpp] view p

    原文地址

    http://blog.csdn.net/zha_1525515/article/details/7170059


    大纲:

    1.  函数返回局部对象的拷贝的一般实现方式。
    2.  NRV(Named Return Value)优化。
    3.  NRV优化触发的疑问。

    一、函数返回局部对象的拷贝的一般实现方式

    比如有这么一段函数定义:

    1. class X;  
    2. X bar()  
    3. {  
    4.     X x1;  
    5.     // 处理 x1..  
    6.     return x1;  
    7. }  

    在学习C++语法时,我们知道了。针对”Xbar()”这样的函数,是返回class X的一个对象的拷贝。其返回值是一个对象,比如叫做x2。在执行return时,x2通过调用拷贝构造函数,拷贝对象x1来实现其初始化。也就是说,这里会存在两个对象x1、x2。那么这种返回对象的拷贝,是怎么实现的呢?一般来说,C++编译器会将上段代码中bar的实现转换成如下的代码。

    1. // 函数实现  
    2. void bar(X& __result)   // 加上一个额外参数  
    3. {  
    4.     // 预留x1的内存空间  
    5.     X x1;  
    6.   
    7.     // 编译器产生的默认构造函数的调用,  
    8.     x1.X::X();  
    9.   
    10.     // 处理 x1..  
    11.   
    12.     // 编译器产生的拷贝操作  
    13.     __result.X::X(x1);  
    14.   
    15.     return;  
    16. }  
    17.   
    18. // 函数调用  
    19. X x2;                   // 这里只是预留内存,并未调用初始化函数  
    20. bar(x2);  
    通过上述代码,我们可见编译器对于返回对象拷贝的处理方式。

    1、函数添加一个额外参数,为返回对象的引用;

    2、函数调用前,先申请欲返回对象x2的内存空间;

    3、将对象x2的引用传入函数中,并在函数返回前,调用x2的拷贝构造函数。

    通过上述实现方式

    1. X x2 = bar();  
    被转换成了
    1. X x2;  
    2. bar(x2);  


    二、NRV(Named Return Value)优化

    上面的实现中,存在着x1、x2两个对象,而x1的生命周期转瞬即逝。而且对于bar()的调用者来说,根本就没有x1这个对象,调用者想要的只有x2。这样的实现能不能够将其优化变得更快呢。编译器有一种优化方式,直接将x2替代x1。编译器转换后的伪代码如下。

    1. void bar(X& __result)  
    2. {  
    3.     // 调用__result的默认构造函数  
    4.     __result.X::X();  
    5.   
    6.     // 处理__result  
    7.     return;  
    8. }  

    从代码看出,这里只有一个对象,也就是传入的x2。NRV优化后的实现,比原来的实现省去了如下操作:

    1)  在堆栈中预留x1的内存;

    2)  调用X的默认构造函数,构造x1

    3)  调用X的贝构造函数,构造x2

    4)  调用x1的析构函数

    5)  堆栈中回收x1的内存

    但是多了一个操作,就是调用X的默认构造函数,构造x2。 对于函数的调用者(只关心x2不关心x1)来说,只有一个区别,就是x2的构造方式由调用拷贝构造函数,转变成了调用默认构造函数

    三、NRV优化触发的疑问

    上面的内容在《深度探索C++对象模型》中都有详细的讲解。此外书中还提到了程序员必须给class X定义拷贝构造函数才能触发NRV优化,不然还是按照最初的较慢的方式执行。可是为什么一定要定义拷贝构造函数才能触发NRV优化呢。在网上找了半天一直没有确定的答案。于是我做了如下实验。有如下代码:

    1. class CTest  
    2. {  
    3. public:  
    4.     CTest()  
    5.     {  
    6.         cout << "CTest()" << this << endl;  
    7.     }  
    8.     CTest(const CTest& rcTest)  
    9.     {  
    10.         cout << "CTest(CTest)" << this << endl;  
    11.     }  
    12.     ~CTest()  
    13.     {  
    14.         cout << "~CTest()" << this << endl;  
    15.     }  
    16. private:  
    17.     int a;  
    18. };  
    19.   
    20. CTest foo()  
    21. {  
    22.     CTest oTestInFoo;  
    23.     return oTestInFoo;  
    24. }  
    25.   
    26. int main()  
    27. {  
    28.     CTest oTest = foo();  
    29.     return 0;  
    30. }  
    在不同的编译环境的执行结果分别为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    也就是说,在vs2005的release环境和g++中,都触发了编译器的NRV优化。

    然后,再将代码中的class CTest的拷贝构造函数去掉,执行结果依次为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    我们去掉class CTest的拷贝构造函数后,按照《深度探索》中所说,class CTest的拷贝动作只需要bitwise copy就可以实现。所以编译器也不会给其合成一个implicit的拷贝构造函数。也就是说,这个时候class CTest是没有拷贝构造的。但执行结果和去掉拷贝构造前一样,vs2005译的release程序和g++中,均使用了NRV优化。

    最后将CTest的代码改为

    1. class CSub  
    2. {  
    3. public:  
    4.     CSub(){}  
    5.     CSub(const CSub& rcSub)  
    6.     {  
    7.         cout << "CSub(CSub)" << endl;  
    8.     }  
    9.   
    10. };  
    11.   
    12. class CTest  
    13. {  
    14. public:  
    15.     CTest()  
    16.     {  
    17.         cout << "CTest()" << this << endl;  
    18.     }  
    19.     ~CTest()  
    20.     {  
    21.         cout << "~CTest()" << this << endl;  
    22.     }  
    23. private:  
    24.     int a;  
    25.     CSub oSub;  
    26. };  
    这个时候的执行结果为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    此时因为class CTest中有oSub,且oSub需要调用其拷贝构造函数才能完成拷贝,所以编译器会给其添加一个implicit的拷贝构造函数。而就算这样,执行结果依然和前面的一样。

    实验结果显示,不管是类有explicit的构造、implicit的拷贝构造还是没有拷贝构造,在vs2005的Release和g++下都会触发NRV优化,在vs2005(Debug)下都没有NRV优化。所以可以得出结论,在这两个编译器中,NRV优化和拷贝构造函数是否定义没关系

    那么为什么《深度探索》的作者会说有关系呢。网上找到了一种说法,我觉得比较有道理(传送门截取其中的话就是“早期的 cfront需要一个开关来决定是否应该对代码实行NRV优化,这就是是否有客户(程序员)显式提供的拷贝构造函数:如 果客户没有显示提供拷贝构造函数,那么cfront认为客户对默认的逐位拷贝语义很满意,由于逐位拷贝本身就是很高效的,没必要再对其实施NRV优化;但 如果客户显式提供了拷贝构造函数,这说明客户由于某些原因(例如需要深拷贝等)摆脱了高效的逐位拷贝语义,其拷贝动作开销将增大,所以将应对其实施NRV 优化,其结果就是去掉并不必要的拷贝函数调用。

    我认为,因为作者在书中一直都是以cfront来举例说明的,所以其才会有NRV开关的说法。

    其实不管cfront如何,现在已经确定的是vs2005(Release)和g++都会执行NRV优化。而NRV优化会导致原本预想中的调用拷贝构造函数变成调用别的构造函数(视函数中的对象调用的构造函数而定)。这一点一定要注意,因为一旦这个时候,拷贝构造函数和别的构造函数提供的功能不同(其实一直都不应该这样),会导致debug和release出现执行结果不同的情况。

    展开全文
  • NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系, 早期的 cfront需要一个开关来决定是否应该对代码实行...

    《深度探索C++对象模型》第二章67页有: 
    这个程序的第一个版本不能实施NRV优化,因为test class 缺少一个copy constructor. 
    也就是缺少拷贝构造函数所以不能NRV优化。

    NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系,

    早期的 cfront需要一个开关来决定是否应该对代码实行NRV优化,这就是是否有客户(程序员)显式提供的拷贝构造函数:如果客户没有显式地提供拷贝构造函数,那么cfront认为客户对默认的逐位拷贝语义很满意,由于逐位拷贝本身就是很高效的,所有没必要再对其实施NRV优化;但如果客户显式提供了拷贝构造函数,这说明客户由于某些原因(例如需要深拷贝等)摆脱了高效的逐位拷贝语义,其拷贝动作开销将增大,所以将应对其实施NRV 优化,其结果就是去掉并不必要的拷贝函数调用。

    NRV优化会导致原本预想中的调用“拷贝构造函数”变成调用别的“构造函数”, 
    一旦这个时候,拷贝构造函数和别的构造函数提供的功能不同,就可能会出问题。

    参考: 
    https://www.cnblogs.com/cyttina/archive/2012/11/26/2790076.html 
    https://book.douban.com/annotation/19292671/
    --------------------- 
    作者:uestc_chenmo 
    来源:CSDN 
    原文:https://blog.csdn.net/uestc_chenmo/article/details/80342719 
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • NRV优化详解

    千次阅读 2016-10-19 21:07:13
    原文地址 http://blog.csdn.net/zha_1525515/article/details/7170059 ... NRV优化触发的疑问。 一、函数返回局部对象的拷贝的一般实现方式 比如有这么一段函数定义: [c

    原文地址

    http://blog.csdn.net/zha_1525515/article/details/7170059


    大纲:

    1.  函数返回局部对象的拷贝的一般实现方式。
    2.  NRV(Named Return Value)优化。
    3.  NRV优化触发的疑问。

    一、函数返回局部对象的拷贝的一般实现方式

    比如有这么一段函数定义:

    [cpp]  view plain copy
    1. class X;  
    2. X bar()  
    3. {  
    4.     X x1;  
    5.     // 处理 x1..  
    6.     return x1;  
    7. }  

    在学习C++语法时,我们知道了。针对”Xbar()”这样的函数,是返回class X的一个对象的拷贝。其返回值是一个对象,比如叫做x2。在执行return时,x2通过调用拷贝构造函数,拷贝对象x1来实现其初始化。也就是说,这里会存在两个对象x1、x2。那么这种返回对象的拷贝,是怎么实现的呢?一般来说,C++编译器会将上段代码中bar的实现转换成如下的代码。

    [cpp]  view plain copy
    1. // 函数实现  
    2. void bar(X& __result)   // 加上一个额外参数  
    3. {  
    4.     // 预留x1的内存空间  
    5.     X x1;  
    6.   
    7.     // 编译器产生的默认构造函数的调用,  
    8.     x1.X::X();  
    9.   
    10.     // 处理 x1..  
    11.   
    12.     // 编译器产生的拷贝操作  
    13.     __result.X::X(x1);  
    14.   
    15.     return;  
    16. }  
    17.   
    18. // 函数调用  
    19. X x2;                   // 这里只是预留内存,并未调用初始化函数  
    20. bar(x2);  
    通过上述代码,我们可见编译器对于返回对象拷贝的处理方式。

    1、函数添加一个额外参数,为返回对象的引用;

    2、函数调用前,先申请欲返回对象x2的内存空间;

    3、将对象x2的引用传入函数中,并在函数返回前,调用x2的拷贝构造函数。

    通过上述实现方式

    [cpp]  view plain copy
    1. X x2 = bar();  
    被转换成了
    [cpp]  view plain copy
    1. X x2;  
    2. bar(x2);  


    二、NRV(Named Return Value)优化

    上面的实现中,存在着x1、x2两个对象,而x1的生命周期转瞬即逝。而且对于bar()的调用者来说,根本就没有x1这个对象,调用者想要的只有x2。这样的实现能不能够将其优化变得更快呢。编译器有一种优化方式,直接将x2替代x1。编译器转换后的伪代码如下。

    [cpp]  view plain copy
    1. void bar(X& __result)  
    2. {  
    3.     // 调用__result的默认构造函数  
    4.     __result.X::X();  
    5.   
    6.     // 处理__result  
    7.     return;  
    8. }  

    从代码看出,这里只有一个对象,也就是传入的x2。NRV优化后的实现,比原来的实现省去了如下操作:

    1)  在堆栈中预留x1的内存;

    2)  调用X的默认构造函数,构造x1

    3)  调用X的贝构造函数,构造x2

    4)  调用x1的析构函数

    5)  堆栈中回收x1的内存

    但是多了一个操作,就是调用X的默认构造函数,构造x2。 对于函数的调用者(只关心x2不关心x1)来说,只有一个区别,就是x2的构造方式由调用拷贝构造函数,转变成了调用默认构造函数

    三、NRV优化触发的疑问

    上面的内容在《深度探索C++对象模型》中都有详细的讲解。此外书中还提到了程序员必须给class X定义拷贝构造函数才能触发NRV优化,不然还是按照最初的较慢的方式执行。可是为什么一定要定义拷贝构造函数才能触发NRV优化呢。在网上找了半天一直没有确定的答案。于是我做了如下实验。有如下代码:

    [cpp]  view plain copy
    1. class CTest  
    2. {  
    3. public:  
    4.     CTest()  
    5.     {  
    6.         cout << "CTest()" << this << endl;  
    7.     }  
    8.     CTest(const CTest& rcTest)  
    9.     {  
    10.         cout << "CTest(CTest)" << this << endl;  
    11.     }  
    12.     ~CTest()  
    13.     {  
    14.         cout << "~CTest()" << this << endl;  
    15.     }  
    16. private:  
    17.     int a;  
    18. };  
    19.   
    20. CTest foo()  
    21. {  
    22.     CTest oTestInFoo;  
    23.     return oTestInFoo;  
    24. }  
    25.   
    26. int main()  
    27. {  
    28.     CTest oTest = foo();  
    29.     return 0;  
    30. }  
    在不同的编译环境的执行结果分别为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    也就是说,在vs2005的release环境和g++中,都触发了编译器的NRV优化。

    然后,再将代码中的class CTest的拷贝构造函数去掉,执行结果依次为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    我们去掉class CTest的拷贝构造函数后,按照《深度探索》中所说,class CTest的拷贝动作只需要bitwise copy就可以实现。所以编译器也不会给其合成一个implicit的拷贝构造函数。也就是说,这个时候class CTest是没有拷贝构造的。但执行结果和去掉拷贝构造前一样,vs2005译的release程序和g++中,均使用了NRV优化。

    最后将CTest的代码改为

    [cpp]  view plain copy
    1. class CSub  
    2. {  
    3. public:  
    4.     CSub(){}  
    5.     CSub(const CSub& rcSub)  
    6.     {  
    7.         cout << "CSub(CSub)" << endl;  
    8.     }  
    9.   
    10. };  
    11.   
    12. class CTest  
    13. {  
    14. public:  
    15.     CTest()  
    16.     {  
    17.         cout << "CTest()" << this << endl;  
    18.     }  
    19.     ~CTest()  
    20.     {  
    21.         cout << "~CTest()" << this << endl;  
    22.     }  
    23. private:  
    24.     int a;  
    25.     CSub oSub;  
    26. };  
    这个时候的执行结果为:

    VS2005(Debug)

    VS2005(Release)

    g++(-c -o)

    此时因为class CTest中有oSub,且oSub需要调用其拷贝构造函数才能完成拷贝,所以编译器会给其添加一个implicit的拷贝构造函数。而就算这样,执行结果依然和前面的一样。

    实验结果显示,不管是类有explicit的构造、implicit的拷贝构造还是没有拷贝构造,在vs2005的Release和g++下都会触发NRV优化,在vs2005(Debug)下都没有NRV优化。所以可以得出结论,在这两个编译器中,NRV优化和拷贝构造函数是否定义没关系

    那么为什么《深度探索》的作者会说有关系呢。网上找到了一种说法,我觉得比较有道理(传送门)。截取其中的话就是“早期的 cfront需要一个开关来决定是否应该对代码实行NRV优化,这就是是否有客户(程序员)显式提供的拷贝构造函数:如 果客户没有显示提供拷贝构造函数,那么cfront认为客户对默认的逐位拷贝语义很满意,由于逐位拷贝本身就是很高效的,没必要再对其实施NRV优化;但 如果客户显式提供了拷贝构造函数,这说明客户由于某些原因(例如需要深拷贝等)摆脱了高效的逐位拷贝语义,其拷贝动作开销将增大,所以将应对其实施NRV 优化,其结果就是去掉并不必要的拷贝函数调用。

    我认为,因为作者在书中一直都是以cfront来举例说明的,所以其才会有NRV开关的说法。

    其实不管cfront如何,现在已经确定的是vs2005(Release)和g++都会执行NRV优化。而NRV优化会导致原本预想中的调用拷贝构造函数变成调用别的构造函数(视函数中的对象调用的构造函数而定)。这一点一定要注意,因为一旦这个时候,拷贝构造函数和别的构造函数提供的功能不同(其实一直都不应该这样),会导致debug和release出现执行结果不同的情况。

    展开全文
  • NRV优化 NRV优化指发生在 函数以值返回时的拷贝构造的优化。如下这个demo,函数以值函数会发生拷贝构造,但是某些场景这个拷贝构造可以被省去。 class T { }; T Fun(); 如下面这个场景发生了俩个构造,一个是默认...
  • 理解NRV优化

    千次阅读 多人点赞 2012-01-01 13:44:37
     NRV优化触发的疑问。 一、函数返回局部对象的拷贝的一般实现方式 比如有这么一段函数定义: class X; X bar() { X x1; // 处理 x1.. return x1; } 在学习C++语法时,我们知道了。针对”Xbar()...
  • 编译器的NRV优化

    2015-01-11 17:24:11
    一、NRV的简单理解  NRV是Named Return Value的简称。NRV优化简单的说:有一条语句,A a = f();...但是如果用了NRV优化,那就不必要调用拷贝构造函数,编译器可以这样做,把a的地址传递进函数f
  • 觉得很有意思,于是写了一段小的代码,来测试下有NRV优化和无NRV优化有什么区别。 测试环境:Win7 编译软件: VS2008 说明:VS2008上Debug和Release版本已经天然区别开了NRV优化情况。 Debug版本无NRV...
  • 自己动手理解NRV优化

    2016-10-01 21:39:09
    一、NRV的简单理解  NRV是Named Return Value的简称。NRV优化简单的说:有一条语句,A a = f();...但是如果用了NRV优化,那就不必要调用拷贝构造函数,编译器可以这样做,把a的地址传递进函数f(),
  • NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系, 早期的 cfront需要一个开关来决定是否应该对代码实行...
  • NRV优化所带来的困惑

    2013-12-18 12:12:43
    我们知道要了解编译器在做什么,NRV优化应该是一个无法避免的问题,下面来看一个例子 #include "iostream" //从这两个程序的运行来看NRV优化好像并不是那么如你想象中的好 using namespace std; #include class ...
  • 看了一下程序,这个NRV优化和copy constructor木有关系的说啊,所以为什么没有copy constructor就不能进行NRV优化了呢。 搜了一下,结果很坑爹,就是 侯捷也不知道,Lippman也没有给出答案,而且...
  • 摘要: c++中创建对象以及销毁对象时,会自动调用对象的...同时编译器也会针对不同情况的函数调用,在不产生错误的情况下采用“NRV优化”(函数返回时,不产生临时变量)。 示例代码:#include using namespace std;
  • C++11中的移动构造函数又把NRV优化翻出来了,都是采用临时中间值优化,两者不能共存。 参数传递如何实现? 【实现模型1】引入临时对象,使用拷贝构造函数初始化。然后利用bitwise copy将其拷贝到x0的位置。比如: ...
  • 原文地址:http://blog.csdn.net/zha_1525515/article/details/7170059 感谢作者! ... NRV优化触发的疑问。 一、函数返回局部对象的拷贝的一般实现方式 比如有这么一段函数定义:
  • 关于NRV优化

    千次阅读 2014-10-29 16:17:56
    什么是NRV优化呢,顾名思义,就是保存返回值的变量不再使用没名没姓的__temp0这样的东西了,而是直接把c作为返回变量,因此应该将NRV翻译为“有名字的返回变量”吧,侯捷翻译的《深入探索C++对象模型》居然把它称为...
  • 关于NRV优化详细分析

    千次阅读 2016-12-30 12:11:12
    (注意:我尝试把Vector的拷贝构造函数删掉,同样生成了上面这段代码(一个字节都没变),因此我推测,拷贝构造函数并不是触发NRV优化的条件了,Lippman的书可能有点过时了。) 但是这样带来的坏处是,如果你在...
  • VS2017怎么触发NRV优化
  • [C++] NRV优化

    千次阅读 2014-03-12 09:40:52
    对于函数返回对象时,编译器的NVR优化
  • 话说如果一个class没有提供copy constructor,就不会实施NRV优化,这是为什么,因为编译器需要的话,可以合成一个copy constructor啊 求大神解答, 谢谢。
  • 书中说,NRV优化和拷贝构造函数是有关系的,只有定义了拷贝构造函数才会开启NRV优化,但现代编译器NRV优化的开启一般都与拷贝构造函数没有关系,下面一段话摘自网络,参考关于cfront的NRV优化,解释了为什么lippman...
  • 本篇博客就为他家介绍一个编译器的优化操作:NRV,以及关于初始化列表的一些容易踩的“坑”!NRVNRV是named Return Value的缩写,翻译过来就是具名返回值优化,这个优化到底在编译层干了些什么事,我们先来看个例子...
  • (里面说了在vc++ 8.0才加入了NRV优化NRV优化的开关是有/O后面的级别开启。g++到底有没有,依上面的结果则是没有nrv优化)  The Visual C++ 8.0 compiler makes use of the flexibility that the standard ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 990
精华内容 396
热门标签
关键字:

nrv优化