Effective C++——必须返回对象时,别妄想返回其引用或指针

pass-by-valuepass-by-reference比较起来效率低很多,优先选择后者。但要注意有时候返回引用或指针会带来问题。

class Rational
{
    public:
    friend const Rational& operator*(const Rational& lhs,const Rational& rhs)
    {
        Rational res(lhs.n*rhs.n,lhs.d*rhs.d);
        return res;
    }
    Rational(int l,int r){}
    private:
    int n;
    int d;
};

*操作符重载函数有没有问题?
1.效率上来看,这里需要调用一次构造函数生成一个对象,然后将其返回,res作为局部对象在销毁时会调用一次析构函数。
2.res作为局部对象会被销毁,内存空间会被清理,如此,返回的是一个已经不存在的对象的引用。
这是由于栈对象的特点决定的,引用的前提是对象必须已经存在!那么返回一个堆对象引用或指针可行不?

class Rational
{
    public:
    friend const Rational& operator*(const Rational& lhs,const Rational& rhs)
    {
        Rational*  res = new Rational (lhs.n*rhs.n,lhs.d*rhs.d);
        return *res;
    }
    Rational(int l,int r){}
    private:
    int n;
    int d;
};

说明1:从效率上来看,调用一次构造函数进行初始化。
说明2:delete 动作交给 了客户端
说明3:Rational w,x,y,z;w =x*y*z;客户端这样使用时,会有什么问题?
调用了两次*动作,就是new 两次了,当然需要delete 两次,但无法获取delete 所需要的指针。
堆栈空间上分配的对象都不能完成返回值是对象的需求,那么static 对象怎么样?

class Rational
{
    public:
    friend const Rational& operator*(const Rational& lhs,const Rational& rhs)
    {
        static Rational res ;
        res.n = lhs.n*rhs.n;
        res.d = lhs.d*rhs.d;    
        return res;
    }
    friend bool operator == (const Rational& lhs,const Rational& rhs){}
    Rational(int l,int r){}
    private:
    int n;
    int d;
};

说明1:所有static 对象都有的一个安全隐患,多线程应用时
说明2:考虑客户端这样的使用情形:

Rational a,b,c,d;
            if(a*b == c*d)
            {}
            else
            {}
            <==>
            if(operator==(operator*(a,b)),(operator*(c,d)))
**operator*返回的是一个static对象的引用,不同的对象运算得到的static对象虽然不同,但static对象只有一份,最终比较的时候由于指向的是同一个static 对象,所以永远为true。**
那么使用静态数组对象怎么样?效率大大降低了。首先数值需要指定大小,就算使用vector 替代之,还有另外一个问题,对象之间的赋值,拷贝构造函数和析构函数的调用问题。
最好的办法是:pass-by-value
class Rational
{
    public:
        /*friend const Rational operator*(const Rational& lhs, const Rational& rhs)
    {
        Rational res;
        res.n = lhs.n*rhs.n;
        res.d = lhs.d*rhs.d;
        return res;//拷贝构造匿名对象,至于匿名对象的析构则要看其如何被接收
    }//析构res 局部对象
*/
    friend const Rational operator*(const Rational& lhs, const Rational& rhs)
    {       
        return Rational(lhs.n*rhs.n, lhs.d*rhs.d);//一次有参构造函数生成匿名对象,效率更高
    }
    Rational(int l,int r){}
    private:
    int n;
    int d;
};

说明:为了满足返回值是对象的需求,拷贝构造函数被调用,生成一个匿名对象,然后将其返回,而res会被销毁。但这样仍然没有解决多次调用构造函数和析构函数带来的效率问题,庆幸的是C++ 编译器可以在特殊情况下进行优化。

Rational a, b, c;
c = a*b;
Rational d = a*b;
说明:对象c 和对象d 的区别在于
Rational d = a*b;
匿名对象初始化对象d,此时匿名对象和d合二为一,d对象生命周期结束时调用析构函数释放匿名对象。此过程没有调用拷贝构造函数或=运算符重载函数,这是编译器的优化,在于过程是初始化过程,效率更高。
Rational a, b, c;//初始化
c = a*b;//赋值
过程是赋值过程,非初始化过程。所以需要调用=操作符重载函数,效率低。

总结:操作符重载函数采用有参数构造函数生成匿名对象,客户端采用初始化方式接收,直接将匿名对象提升为所需对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值