令人困惑的return by value

    技术2022-05-11  92

     

    问题从这里开始。class X;const X operator+( const X& x1, const X& x2 );X foo(){return X(a+b);}和X foo(){X xx(a+b);return xx;}这两个函数,有什么区别?这个问题牵涉到C++的内部处理,下面是其更通用的模式。X foo(){X xx;// process...return xx;}C++如何处理return by value,传统的方法是修改函数原型。void foo( X& r ){X xx;xx.X(); //ctor// process...r.XX( xx ) // copy ctor}这样就把xx的值给返回了,这里有一个xx的临时对象的ctor和dtor。于是乎。X obj = foo();被转化为 X obj;foo( obj );但是,对于程序员来说,是可以进行一些优化的,其方法就是采用ctor返回,X foo(){return X( ... );}编译器处理过后,为这样。void foo( X &r ){return r.X(...);}看出来了吗?这里少个对象(即上面的xx)的ctor和dtor,效率自然提高。更进一步,如果这个函数是inline的,则X obj = foo();被处理成X obj;obj.X(...);Bingo!!真的是棒呆了,C++注重的效率得以完全体现。这种优化我称之为ARV( anonymous return value )优化,:)然而对于前者NRV( named return value ),我们又该如何呢?答案是:没有办法,唯一可作的是期待编译器给我们一些帮助。如果我们的编译器够power的话,那么X foo(){X xx;// process...return xx;}可能被处理成:void foo( X &r ){// ctorr.X();// process...}在这里,同样没有出现named object(指xx)的ctor和dtor,但是作为一个应该把握全局的程序员,我劝你不要太指望它。首先,它还是调用了default ctor,这在ARV中是不存在的。其次,你无法知道编译器是否正在这样做,毕竟对于厂家来说,它有这样的权利不让你知道细节。再次,编译器就算有这样的能力,但仅仅对一些简单的函数有效,而对于实际编程来说,函数往往很复杂,比如具有多个分支返回的函数,编译器就只能叹气了。还有,在函数开头就声明对象的作法,可不是正宗C++的style,C++一向提倡“只有在必要是才使用”,真正的C++程序员应该牢记这一点。最后,从C++编译器历史来看,在优化过程中,匿名对象比命名对象更容易消除,你要充分利用它。答案:对于这么一个简单的函数,如果你的编译器支持NRV优化,则结果是一样的,否则。。。而ARV优化总是支持的。那采用ARV这样做有没有缺点呢?或许吧,毕竟你要写一堆ctor用于特殊用途了。:)注:本文中的例子选自<<Inside C++ Object Model>>,要感谢Lippman给C++程序员们写了这么一本好书,同样感谢JJhou给中国程序员的翻译。本文还参考了MEC(More Effective C++)


    最新回复(0)