为什么?

《More C++ idioms》: 3. Algebraic Hierarchy
 程序执行的流程与自己想的不一样:

 Number Number::makeReal(double r){Number tx; return tx}

 main:

       Number t = Number::makeReal();

   自己想的应该是:先生成tx(默认构造); 返回时需要一个临时量temp,并以tx初始化(拷贝构造),而后用temp初始化 t (拷贝构造);

   实际执行流程是:生成tx(默认构造),tx就是t

理解好C语言,自然就知道原因了,见:http://www.cnblogs.com/openix/p/3178259.html

更深入一步:

如果我们以上面给出的原因链接来 理解:

《C++ Primer 》4_th_CN p_214 的 “4、千万不要返回局部对象的引用”

也许我们会认为 第4点有问题,因为按照“C语言”理解,返回的Number实际上就是在main函数中创建的number, 但是我们应该明白 第4点是绝对没错的,原因只有一点:

当返回引用时 一定会构建被调用函数的临时量,该临时量与发起调用中的被初始量一定不同。

启示:

返回引用是否一定高效,而直接返回一个结构体是否就一定低效。答案:NO

对比以下三个程序:

其中A最高效;B可以完成同样的功能,但是效率太低,而且造成内存泄漏;C根本就是错的(尽管可以完成同样的功能,但是请记住p_214的第4点)

//A 
default constructor this : 0xbff65e4c
temp this : 0xbff65e4c
deconstructor this : 0xbff65e4c

class Base
{
public:
Base(const Base &thiz) : val(thiz.val)
{
cout << "copy constructor this : " << this << endl;
cout << "thiz : " << &thiz << endl;
} static Base makeBase(int v)
{
Base temp(v);
return temp;
} private:
int val;
Base(int v) : val(v)
{
cout << "default constructor this : " << this << endl;
} }; int main(void)
{
Base temp = Base::makeBase();
cout << "temp this : " << &temp << endl;
return ;
}

//B 效率太低,而且内存泄漏

default constructor this : 0x84f1008
copy constructor this : 0xbfa6386c
thiz : 0x84f1008
temp this : 0xbfa6386c
deconstructor this : 0xbfa6386c  //0x84f1008内存泄漏,即使最后进程终止时未被回收的内存,系统将自动回收,可是我们不应依赖于此行为
class Base
{
public:
Base(const Base &thiz) : val(thiz.val)
{
cout << "copy constructor this : " << this << endl;
cout << "thiz : " << &thiz << endl;
} static Base& makeBase(int v)
{
Base *p = new Base(v);
return *p;
} ~Base(void)
{
cout << "deconstructor this : " << this << endl;
} private:
int val;
Base(int v) : val(v)
{
cout << "default constructor this : " << this << endl;
} };

//C完全就是错的

In static member function ‘static Base& Base::makeBase(int)’:
warning: reference to local variable ‘temp’ returned [enabled by default] default constructor this : 0xbf8594cc
deconstructor this : 0xbf8594cc
copy constructor this : 0xbf8594fc  //显然错了
thiz : 0xbf8594cc
temp this : 0xbf8594fc
deconstructor this : 0xbf8594fc
class Base
{
public:
Base(const Base &thiz) : val(thiz.val)
{
cout << "copy constructor this : " << this << endl;
cout << "thiz : " << &thiz << endl;
} static Base& makeBase(int v)
{
Base temp(v);
return temp;
} ~Base(void)
{
cout << "deconstructor this : " << this << endl;
} private:
int val;
Base(int v) : val(v)
{
cout << "default constructor this : " << this << endl;
} }; int main(void)
{
Base temp = Base::makeBase();
cout << "temp this : " << &temp << endl;
return ;
}

现在我们知道A的效率最高,那么我们是否应该向A这样设计程序,我认为:尽量不要如此,对于Algebraic Hierarchy程序如此设计确实很好,而且使用起来很方便,但是请注意对于A中的makeBase函数,其中只有一个temp变量,因此很容易将main中的t与该变量对应起来,但是如果makeBase中的Base类型变量一旦多起了,编译器自然可以从容应对,但是我们已经不便于我们分析了(因为我们不知是否需要经过一个编译器插入的临时量,并将其通过拷贝构造函数初始化t)。

我错过了比赛……

如果返回结构体类型变量(named return value optimisation,NRVO) ------ 续的更多相关文章

  1. 如果返回结构体类型变量(named return value optimisation,NRVO)

    貌似这是一个非常愚蠢的问题,因为对于具有良好素质的程序员而言,在C中函数返回类型为结构体类型是不是有点不合格,干嘛不用指针做传入传出呢? 测试环境:Linux IOS 3.2.0-45-generic ...

  2. C语言函数不能返回数组,但可以返回结构体

    为什么C语言函数可以返回结构体,却不可以返回数组?有这样的问题并不奇怪,因为C语言数组和结构体本质上都是管理一块内存,那为何编译器要区别对待二者呢? C语言函数为什么不能返回数组? 在C语言程序开发中 ...

  3. 【C语言入门教程】7.1 结构体类型变量的定义和引用

    前面学习了变量和数组这些简单的数据结构,它们的特点是必须使用规定的数据类型.例如数组被定义为整型后,它的所有存储单元都是由整型构成.现实生活中某一类事物的共同属性可能是由不同的数据类型组成的集合,或者 ...

  4. c++调用python系列(1): 结构体作为入参及返回结构体

    最近在打算用python作测试用例以便对游戏服务器进行功能测试以及压力测试; 因为服务器是用c++写的,采用的TCP协议,当前的架构是打算用python构造结构体,传送给c++层进行socket发送给 ...

  5. abap函数返回结构体类型

    1: 定义一个结构体 T-CODE   se11 2: 选择 structure 3:输入相应的字段 4:激活 5:创建一个function module zfm_return_table,返回类型为 ...

  6. Android JIN返回结构体

    一.对应类型符号 Java 类型     符号 boolean     Z byte     B char     C short     S int     I long     J float   ...

  7. C++学习(二十四)(C语言部分)之 结构体1

    1.结构体 存放多个不同类型的数据 但是是相关联的 数组 存放多个相同类型的数据 结构体是存放多个相关联的不同类型的数组 struct 定义一个结构体类型 自定义类型 2.结构体定义方式 定义类型最通 ...

  8. (C/C++) 用函数返回一个结构体

    方法一: 参数里含有指向指针的指针. 注意:如果函数参数里只有一个指向结构体的指针,是无法正确地返回结构体的值的.原因在于在编译的时候,会对入参p产生一个备份_p. 参考此文:http://www.c ...

  9. 【C语言入门教程】7.3 结构体指针的定义和引用

    C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...

随机推荐

  1. C#学习笔记(17)——C#中接口的作用

    说明(2017-7-17 23:50:48): 原文: 接口的作用 接口的作用(C#)(另一篇) C#接口是一个让很多初学C#者容易迷糊的东西,用起来好像很简单,定义接口,里面包含方法,但没有方法具体 ...

  2. 利用order by 进行盲注

    0x01 利用场景 登录代码: $username = $_POST['username']; $password = $_POST['password']; if(filter($username) ...

  3. java二维码的生成与解析代码

    二维码,是一种采用黑白相间的平面几何图形通过相应的编码算法来记录文字.图片.网址等信息的条码图片.如下图 二维码的特点: 1.  高密度编码,信息容量大 可容纳多达1850个大写字母或2710个数字或 ...

  4. idea properties文件unicode码问题

    在git hub上下载了个工程.但是properties文件一直显示不了中文: # \u662F\u5426\u4F7F\u7528\u8FDC\u7A0B\u914D\u7F6E\u6587\u4E ...

  5. VB6学习笔记

    1.数据库读取 [工程]菜单的[引用]菜单项,打开引用对话框,选中[Microsoft ActiveX Data Objects 6.1 Library] [工程]菜单的[引用]菜单项,打开引用对话框 ...

  6. 【css】关于 hr 在各浏览器中的问题

    在做页面是有时候会用到分割线 hr,但是在 ie6 和 ie7 下显示很蛋疼,本文将教你如何写出兼容各浏览器的 hr. 首页我们先了解下 hr 在各浏览器下的差异,如下表格:   正常浏览器 ie6. ...

  7. SpringCloudConfig与SpringCloudEureka 注册中心与配置中心高可用的意义

    所有的配置会缓存在本地,远程配置中心DOWN机,不影响本地使用,只是无法重新请求服务端获取配置的更新. 不管是注册中心的高可用,还是配置中心的高可用.本质上都是保证服务能注册上去或者能从配置中心获取配 ...

  8. QueenPuzzle-N皇后问题

    详见-算法之美-p180. #include <iostream> #include <memory.h> #include <conio.h> #include ...

  9. Paxos算法细节详解(一)

    Paxos分析 最近研究paxos算法,看了许多相关的文章,概念还是很模糊,觉得还是没有掌握paxos算法的精髓,所以花了3天时间分析了libpaxos3的所有代码,此代码可以从https://bit ...

  10. 微信小程序滚动Tab实现左右可滑动切换

    --------------------------------------------------------wxml---------------------------------------- ...