zoukankan      html  css  js  c++  java
  • 条款23: 必须返回一个对象时不要试图返回一个引用

    class rational {
    public:
      rational(int numerator = 0, int denominator = 1);
    
      ...
    
    private:
      int n, d;              // 分子和分母
    
    friend
      const rational                      // 参见条款21:为什么
        operator*(const rational& lhs,    // 返回值是const,若不是const,那么可以对两数的乘积结果进行修改,这不符合默认的乘法规则,如(a*b)=c,会编译错误
                  const rational& rhs)     
    };
    
    inline const rational operator*(const rational& lhs,
                                    const rational& rhs)
    {
      return rational(lhs.n * rhs.n, lhs.d * rhs.d);
    }

    请记住,引用只是一个名字,一个其它某个已经存在的对象的名字。无论何时看到一个引用的声明,就要立即问自己:它的另一个名字是什么呢?因为它必然还有另外一个什么名字。拿operator*来说,如果函数要返回一个引用,那它返回的必须是其它某个已经存在的rational对象的引用,这个对象包含了两个对象相乘的结果。

    但,期望在调用operator*之前有这样一个对象存在是没道理的。

    如果operator* 一定要返回这样一个数的引用,就必须自己创建这个数的对象。一个函数只能有两种方法创建一个新对象:在堆栈里或在堆上。在堆栈里创建对象时伴随着一个局部变量的定义,采用这种方法,就要这样写operator*:

    // 写此函数的第一个错误方法
    inline const rational& operator*(const rational& lhs,
                                     const rational& rhs)
    {
      rational result(lhs.n * rhs.n, lhs.d * rhs.d);
      return result;
    }

    这个方法应该被否决,因为我们的目标是避免构造函数被调用,但result必须要象其它对象一样被构造。另外,这个函数还有另外一个更严重的问题,它返回的是一个局部对象的引用,函数返回后局部对象会被析构。

    基于堆的对象是通过使用new产生的,所以应该这样写operator*:

    // 写此函数的第二个错误方法
    inline const rational& operator*(const rational& lhs,
                                     const rational& rhs)
    {
      rational *result =
        new rational(lhs.n * rhs.n, lhs.d * rhs.d);
      return *result;
    }

    首先,你还是得负担构造函数调用的开销,因为new分配的内存是通过调用一个适当的构造函数来初始化的(见条款5和m8)。另外,还有一个问题:谁将负责用delete来删除掉new生成的对象呢?

    实际上,这绝对是一个内存泄漏。即使可以说服operator*的调用者去取函数返回值地址,然后用delete去删除它(操作很麻烦——条款31展示了这样的代码会是什么样的),但一些复杂的表达式会产生没有名字的临时值,程序员是不可能得到的。例如:

    rational w, x, y, z;
    
    w = x * y * z;

    两个对operator*的调用都产生了没有名字的临时值,程序员无法看到,因而无法删除。

  • 相关阅读:
    149. Max Points on a Line(js)
    148. Sort List(js)
    147. Insertion Sort List(js)
    146. LRU Cache(js)
    145. Binary Tree Postorder Traversal(js)
    144. Binary Tree Preorder Traversal(js)
    143. Reorder List(js)
    142. Linked List Cycle II(js)
    141. Linked List Cycle(js)
    140. Word Break II(js)
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3916353.html
Copyright © 2011-2022 走看看