Effective C++ 条款21

必须返回对象时,别妄想返回其reference

我们上节分析了对象引用传递的好处,现在说明函数返回引用对象带来的种种坏处。

先来一段代码:

class Rational{
public:
    Rational(int numerator=0, int denominator=1);
    ……
private:
    int n, d;
    friend
    const Rational operator*(const Rational& lhs,
                             const Rational& rhs);
};

const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
    Rational result(lhs.n* rhs.n, lhs.d* rhs.d);
    return result;
}

Rational a(1,2),b(3,4);
Rational &r=a*b;

大家看看以上代码有没有问题,很显然此时的r是返回值的引用。很明显对象本体已在operator*函数范围外被销毁,此时的r指向的对象已经被系统回收,程序很容易出现错误。

那么,如果在函数体内动态创建对象呢?

如下代码:

const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
    Rational* result=new Rational(lhs.n* rhs.n, lhs.d* rhs.d);
    return *result;
}

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

上面代码有什么问题?

很显然造成了内存泄露,两次调用 operator*函数,创建两个动态内存对象,但是最后却没有delete。

如果创建static 对象呢?

const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
    static Rational result;
    result=……;
    return result;
}

bool operator==(const Rational& lhs, const Rational& rhs);
Rational a, b, c, d;
……
if((a*b)==(c*d))
{
    doSomething();
}
else
{
    doOtherthing();
}

上面代码有什么问题?

答案是上面代码中(a*b)==(c*d)的值一直为真。这是static的特性!所以,operator*的函数设计不合理,导致operator==出错。

说到现在总结一下。

很简单就想题目所说函数必须返回对象时,别妄想返回其reference。那返回什么?很明显返回对象的值而不是引用。

时间: 2024-07-31 20:06:20

Effective C++ 条款21的相关文章

More Effective C++ 条款21 利用重载技术避免隐式类型转换

1. 正如条款19和条款20所言,临时对象的构造和析构会增加程序的运行成本,因此有必要采取措施尽量避免临时对象的产生.条款20介绍了一种用于消除函数返回对象而产生临时对象的方法——RVO,但它并不能解决隐式类型转换所产生的临时对象成本问题.在某些情况下,可以考虑利用重载技术避免隐式类型转换. 2. 考虑以下类UPInt类用于处理高精度整数: class UPInt{ public: UPInt(); UPInt(int value); ... }; const UPInt operator+(c

Effective C++ -----条款21:必须返回对象时,别妄想返回其reference

绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象.条款4已经为“在单线程环境中合理返回reference指向一个local static对象”提供了一份设计实例.

Effective C++ 条款21必须返回对象时,别妄想返回其reference

1. 虽然一般情况下传参使用const-by-reference-to-const比较好,但返回值有时必须是对象而不是引用: 当reference绑定到函数内创建的局部对象时,函数调用结束后引用绑定在一个不存在的对象; 当reference绑定到堆内存对象时,函数调用后比较容易忽略内存释放,特别对于以下表达式:w=x*y*z.如果operator*返回指向堆内存的引用,那没内存泄露是必然的; 当reference绑定到函数内部创建的static对象时,对于以下表达式if(a*b==c*d)由于返

Effective C++:条款21:必须返回对象时别妄想返回其reference

(一) 一定要避免传递一些references去指向其实并不存在的对象. 看下面这个类: class Rational { public: Rational(int numerator = 0, int denominator = 1); private: int n, d; friend const Rational operator*(const Rational& lhs, const Rational& rhs); }; 这个函数不能返回引用, (二)在stack中分配local对

effective C++ 读书笔记 条款21

条款21 :必须返回对象时,别妄想返回其reference 条款20里面虽然说传引用比传值好用,但是不能传递一些 reference指向其实并不存在的对象 上代码: #include <iostream> using namespace std; class Rational { public: // Rational() // { // } Rational(int m = 0, int n = 0 ) { } ~Rational() { } private: int n, d; /* 运算

More Effective C++ 条款22 考虑以操作符复合形式(op=)取代其独身形式(op)

1. 一般来说,重载了算数操作符(以下称"独身形式"),那么也就要重载复合赋值操作符(以下称"复合形式").要确保操作符的复合形式例如(operator+=)和独身形式(例如operator+)行为相一致,基于前者实现后者是一个好方法.例如: class Rational{ public: Rational operator+=(const Rational&); ... } Rational operator+(const T&lhs,const

More Effective C++ 条款35 让自己习惯于标准C++ 语言

(由于本书出版于1996年,因此当时的新特性现在来说可能已经习以为常,但现在重新了解反而会起到了解C++变迁的作用) 1. 1990年后C++的重要改变 1). 增加了新的语言特性:RTTI,namespaces,bool,关键词mutable和explicit,enums作为重载函数之自变量所引发的类型晋升转换,以及"在class 定义区内直接为整数型(intergral) const static class members设定初值"的能力. 2). 扩充了Templates的特性

effective c++ 条款4 make sure that objects are initialized before they are used

1 c++ 类的数据成员的初始化发生在构造函数前 class InitialData { public: int data1; int data2; InitialData(int a, int b) { data1 = a: //this is assignment data2 = b; //this is assignment } /* InitialData(int a, int b):data1(a),data2(b) //this is initial {} */ } 2 不同cpp文

More Effective C++ 条款34 如何在一个程序中结合C++和C

1. C++和C混合使用的前提之一就是编译器产生兼容的目标文件(.lib和.dll等).所谓"兼容",指的是编译器在"预编译器相依的特性上"一致,如int和double大小,参数压栈机制等,只有在这个基础上才能讨论结合使用C++和C模块的问题. 2. 在1的基础上,要结合使用C++和C的模块,主要有以下几点需要注意: 1). name mangling(名称重整) Name mangling是C++用于支持函数重载的机制,它对重载的函数名称进行一定改变,使得每个函数