C++函数参数传递与返回值优化技巧

原创 2016年05月30日 22:04:13

       很久没登陆CSDN,最后一次发帖是换工作的散分贴,之后背井离乡,一去就是八年。八年前的自己对技术充满热情,但是有些井底之蛙,也有些偏激。八年过去,恍然大悟,技术无论大小,总应该有些积累,有些沉淀,有些能让自己和后来之人收益之处,于是乎开始着手写技术文章,文章或许浅显,但或多或少可以与君交流提高。废话那么多,那么第一章就说点简单的吧。

      C++函数的数据传递,这里主要指参数传递与返回值。写这篇的目的主要是总结如何高效的使用函数。

      先来说说函数参数的传递,一个简单的示例:

class param_obj{

};
class return_obj{

};

return_obj func(param_obj);

        这里的参数传递采用的是按值传递

        如果读过《effective c++》,或许记得书中第二十条,使用常量引用(pass-by-reference-to-const)来代替按值传递(pass-by-value)。

很明显传递引用省去了拷贝构造函数的执行,对于复杂对象例如其包含指向堆的指针或者是多个基类的子类,那么省下的不止一个函数的执行。关于其他理由,可直接看第二十条描述,这里不做赘述。

      说下常量引用,或许很多人包括我自己曾喜欢直接传递非常量引用。这里按值传递,本身就不希望通过该变量带回数据(也不推荐),所以不给函数参数对象的修改权限是合情合理的。那么有一点值得注意的就是,该对象的get方法,甚至那些计算但不修改对象的方法都应加常量限定符const。常量对象只能调用常量方法

     于是示例代码如下:

class param_obj{
    public:
        int getValue(); const
        int valueSquare(); const 
     private:
        int value;
};
class return_obj{

};

return_obj func(const param_obj&);

       习惯使用常量限定符来描述那些不改变类的方法是有很多好处的,且也最符合设计逻辑


       接下来看函数返回值。

       没错,《effective c++》第21条谈到了返回值,主要谈到不要为了效率而返回引用或者指针等,具体请自行查阅,这里不详述。

       这里笔者主要想提两种方式

       第一是利用RVO(return value optimization),返回值优化。看如下的例子。

#include<iostream>
using namespace std;
class Data{
public:
  Data(){};
  Data(const Data &data){
    cout<<"copy constructor"<<endl;
  };
  Data &operator=(const Data&){
    cout<<"assignment operator"<<endl;
    return *this;
  };
};


Data func(){
  Data f;
  cout<<"f address:"<<&f<<endl;
  return f;
}


int main(void){
  Data a;
  a = func();
  cout<<"a address:"<<&a<<endl;
  Data b = func();
  cout<<"b address:"<<&b<<endl;
  return 0;
}

g++ 4.8 编译执行结果如下

f address:0x7fff2018d72f
assignment operator
a address:0x7fff2018d72e
f address:0x7fff2018d72d
b address:0x7fff2018d72d


      一般函数返回对象时会调用copy构造函数,而这里可以看出两次返回都没有调用copy构造函数,所以这里都进行了RVO。当然此处因为返回的是命名对象,使用的又称为NRVO。

        再看对象b的例子,是不是惊奇的发现赋值操作也被优化掉了,对象b的指针和函数内对象的指针一致。这里我们是否可以得出一条结论:

        在一个变量得到它所需值的时候定义它

        这也正是《effective c++》第26条所强调的,不过那条的描述并不关注这里的优化。

        对于RVO,很多编译器是默认打开,特别是gnu的编译器,所以广大码农可能无意识就享受到了RVO。当然我们能做到的更好的一步就是在赋值函数返回对象时去定义那个对象。

        是不是发现曾经往往以为的要返回指针或是引用才是高效的在这些编译优化中迎刃而解呢。可以仔细阅读自己项目中,是否有很多为了效率而丢失的便利性的写法,例如输出参数是vector时,在外部定义,再通过引用传递给函数这种

vector<int> things;
getThings(things);

void getThings(vector<int> &things){
...
}
        可以大胆的改为

vector<int> things = getThings();

vector<int> getThings(){
    vector<int> things;
    ...
    return things;
}

        这种写法的好处是很多的,调用处更简洁,返回的vector也可以直接嵌套于for语句或作为其他函数输入。


        除了RVO,另一种可以利用的是右值引用。这个是C++11的特性。需打开编译开关。

        如下示例

#include<iostream>
using namespace std;
class Data{
public:
  Data(){};
  Data(const Data &data){
    cout<<"copy constructor"<<endl;
  };
  Data &operator=(const Data&){
    cout<<"assignment operator"<<endl;
    return *this;
  };
  Data &operator=(Data &&){
    cout<<"rvalue assignment operator"<<endl;
    return *this;
  };
};

Data func(){
  Data f;
  return f;
}

int main(void){
  Data a;
  a = func();
  Data b;
  b = a;
  return 0;
}
      输出

rvalue assignment operator
assignment operator

        可以看出, 因为赋值符号右边是函数返回的局部对象,调用了传递右值的赋值操作。右值一般后面不会再被引用,所以这里可做的优化便是右值中的变量可以直接转移,包括指针,无需新申请内存。关于更具体的左右值概念,可以查看网上资料。这里不做详述。

        了解RVO 与 右值引用在很多情况下可以写出更合理与高效的编码。 当然根据项目实际情况,返回指针或是引用也会出现,当然相信仔细琢磨也能找出更优雅的解决方案。


       做个小结:

       关于参数传递:

             使用常引用代替值传递

             学会用const限定方法。

       关于返回值:

             RVO与NRVO解决了临时对象的copy

             学会在函数返回赋值时定义对象

             右值引用能有效改善赋值的效率,特别有指向堆的内容时






    

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

汇编学习第五课之函数参数传递,函数返回值

最近在看《C++反汇编和逆向分析》这本书,还是收获不少. 自己也做实验来验证下心里的想法.函数参数是通过栈结构进行传递,在C++代码中,默认函数调用约定下(有三种函数调用约定,区别在于函数参数入栈顺...

C++函数参数和返回值三种传递方式

C++函数参数和返回值三种传递方式:值传递、指针传递和引用传递 (着重理解) 引用与指针的比较 引用是 C++中的概念,初学者容易把引用和指针混淆一起。一下程序中,n 是m 的 一个引用(r...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

C++函数参数和返回值三种传递方式:值传递、指针传递和引用传递(着重理解)

C++函数参数和返回值三种传递方式:值传递、指针传递和引用传递(着重理解) 引用与指针的比较 引用是 C++中的概念,初学者容易把引用和指针混淆一起。一下程序中,n 是m 的 一个引用(refe...

探讨c++函数中的参数传递与返回值(一) 概念介绍与理解

本文从编译器角度,通过反汇编手段,深入的理解了1.引用的理解与使用2.结构体和类做参数时的底层实现,并对函数参数和返回值的各种情况做了归纳。希望能对大家有用,也希望大家能针对本文中的一些不足和缪误给予...

C++函数参数传递的一大利器——引用(左值)

前言: 本文只浅显地介绍了三种函数参数传递的方式及其优劣,主要目的是为了介绍引用。在另一篇博文中将会用本文中的主要代码反汇编为汇编代码,从编译器处理函数调用的层面更深入地探讨三种函数参数传递的区别。...

C++ 函数参数、返回值效率测试

C++ 函数参数、返回值效率测试

C++,当函数参数或者返回值是对象......(★firecat推荐★)

文章来源:http://blog.chinaunix.net/uid-20816252-id-2791683.html 如果函数的传入参数和返回值是对象,那么这个过程中会发生哪些我们未曾注意过的细节呢...

c/c++使用指针做函数返回值和指针作函数参数问题

一、使用指针做函数返回值:   1、当使用指针做为函数的返回值时,主函数处的char *p;将获得调用函数char *pf;的值,即一个地址值,如oxAE72。此时需要我们注意的是该地址值所指...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)