• [Effective C++ --021]必须返回对象时,别妄想返回其reference


    引言

    在条目20中,我们知道了值传递和引用传递的效率问题,因此在设计程序时,我们可能就尽可能来返回引用而不是值。

    可是,可能会犯下面的一些错误:传递一些引用指向其实并不存在的对象。

    第一节:返回临时变量的引用

    假如我们有以下的例子,先看值传递

     1 class A {
     2 public:
     3     A(int n = 0, int d = 1):n(n),d(d) {}
     4 private:
     5     int n,d;
     6     friend const A operator* (const A& l, const A& r);
     7 };

    在operator*系以值传递的方式返回了一个计算结果,联系到条款20,我们自然会想到,那么用引用传递试试。

    因为函数返回的是A对象,所以函数创建新对象的方式有2:

    1.在stack空间创建

    1 const A& operator* (const A& l, const A& r) {
    2     A result(l.n * r.n, l.d * r.d);
    3     return result;
    4 }

    这样我们避免值传递的调用构造和析构函数,可是result是个临时变量,在函数推出前就被销毁了。任何对这个函数的调用都会是无意义的行为。

    2.在heap空间创建

    1 const A& operator* (const A& l, const A& r) {
    2     A* result = new A(l.n * r.n, l.d * r.d);
    3     return *result;
    4 }

    这样解决了上面临时变量的问题。可是,这个new出来的对象什么时候被释放呢?

    就算我们调用A的时候很谨慎,但还是避免不了出错,比如

    1 A w,x,y,z;
    2 w = x * y * z;     // 实际与operator*(operator*(x, y), z)相同

    这里同一个语句例调用了两次operator*,因此两次使用new,也就需要两次delete,但却没有合理的办法让operator*使用者进行那些delete调用。这就会导致资源泄露。

    经过上面两种方法都不行,可能你还会想到这种方法:我声明一个static对象不行么?

    比如:

    1 const A& operator* (const A& l, const A& r) {
    2     static A result;
    3     result = .....
    4     return result;
    5 }

    看上去完美的解决了这个问题,那么我们这样使用的时候呢?

    1 bool operator == (const A& l, const A& r);
    2 A a,b,c,d;
    3 if ((a*b) == (c*d)) {
    4 ....
    5 }

    结果就会出现:(a*b) == (c*d)总是为true,无论a,b,c,d是什么!

    将(a*b) == (c*d)拆开来理解,我们就可以知道为什么了。

    operator == (operator*(a, b), operator(c*d));

    因为到最后位置,都会返回static对象的现值,也就不怪乎为什么返回true了。

    ◆总结

    1.绝不要返回pointer或者referenc指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象。

  • 相关阅读:
    设计原则
    git 教程
    git新建分支及提交代码到分支
    DataTemplateSelector介绍
    Semaphore 类 的使用理解C#
    C#中Finalize方法的问题
    WPF原理剖析——路由事件
    WPF自学入门(四)WPF路由事件之自定义路由事件
    路由事件
    commandBinding 的命令
  • 原文地址:https://www.cnblogs.com/hustcser/p/4166710.html
Copyright © 2020-2023  润新知