• 条款21:必须返回对象object时,不要返回其引用reference


    如下为一个有理数类,其中包含一个用来计算乘积的函数:

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class Rational
     6 {
     7 public:
     8     Rational(int numerator = 0, int denominator = 1)
     9     {
    10         n = numerator;
    11         d = denominator;
    12     }
    13 
    14 private:
    15     int n, d;
    16     friend const Rational operator*(
    17         const Rational& lhs, const Rational& rhs)
    18         {
    19             Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
    20             return result;
    21         }
    22 };
    23 
    24 int main()
    25 {
    26     Rational a(1, 2);       // a = 1/2
    27     Rational b(3, 5);       // b = 3/5
    28     Rational c = a * b;     // c = 3/10
    29 
    30     return 0;
    31 }

     

    1> 如果上述函数operator*返回一个Rational&会怎么样呢?编译器会发出警告说返回一个local变量的引用。我们知道这个变量是在stack上存放的,在函数退出时就被销毁了,因此是返回了一个指向销毁空间的引用,如果调用这用这个返回的引用来工作,极有可能发生“行为没有定义”的结果。因此切记不要返回一个指向local变量的引用。

     

    2 > 但是我们现在又会想,我可以在heap上创建这个对象啊,这样返回引用就不是指向临时对象了,如下所示:

    1 friend const Rational& operator*(
    2         const Rational& lhs, const Rational& rhs)
    3         {
    4             Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
    5             return *result;
    6         }

    这样做确实可以避免返回临时对象的引用,但是还是存在问题:new出来的对象谁来负责delete啊?,如下使用时:

    Rational w, x, y, z;

    w = x * y * z;

    相当于调用operator*(operator*(x, y), z),即new了两次,那么就需要delete两次,但是使用者却没办法得到reference背后的指针,因此发生内存泄漏了。

     

    3> 当然了或许你还知道一种避免调用构造函数的解决办法,那就是使用local static特性:

    1 const Rational& operator(const Rational& lhs, const Rational& rhs)
    2 {
    3     static Rational result;        // static对象,此函数返回该对象的reference
    4     result = ...;
    5 return result;
    6 }

    如果执行如下调用:

    if((a * b) == (c * d)),会发现 if 条件永远为真,不论如何选择abcd,这是什么原因?这就是static的特性了,在等号两边比较的数都由static变量指定,虽然计算a * b和c * d时,result都会改变,但是不论哪个乘积先被计算,最终只有一份static变量,就是说最后比较时,等价于要么是:a * b == a * b,要么是c * d == c * d。

     

    因此结论是:

    • 无论是stack还是heap,如果应该返回object时,最好不要返回reference
    • 绝不要返回指向local stack对象的reference或者pointer
    • 绝不要返回指向local static对象reference或者pointer
    • 绝不要返回指向heap object的reference
  • 相关阅读:
    HTML基础(一)基本语法知识
    本地方法接口
    本地方法栈
    虚拟机栈相关的问题
    栈帧的内部结构--一些附加信息
    基于角色的权限控制设计
    SpringBoot普通消息队列线程池配置
    栈帧的内部结构--动态返回地址(Return Address)
    栈帧的内部结构--动态链接 (Dynamic Linking)
    栈帧的内部结构--操作数栈(Opreand Stack)
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4537964.html
Copyright © 2020-2023  润新知