没有躲过的坑--重载赋值运算符的自我赋值

C++中有个很重要的事情,就是对于类重载赋值运算符,而达到我们想要的结果。

先看看这几行代码:

//Window 是一个类
Window w;
w = w;          // 再傻的人也不会这么干
w[i] = w[j];    // 这个情况偶尔会发生

作为一个优秀的工程师,就要考虑到任何可能的情况。

看一段更加完整的代码:

class ScrollBar {};

class Window
{
    ScrollBar *sb;
public:
    Window(ScrollBar *s) : sb(s) {}
    Window() = default;
    Window& operator=(const Window&);
};

Window& Window::operator=(const Window& rhs)
{
    delete sb;
    sb = new ScrollBar(*rhs.sb);
    return *this;
}

int main()
{
    Window w(new ScrollBar);
    Window w2(w);
}

这段代码到底有什么坑儿呢?

设想一下,如果 *this 和rhs 是同一个实例对象呢?

那么

delete sb;
sb = new ScrollBar(*rhs.sb);

就会造成严重的问题。

再delete sb后, 我们试图去访问一个已经被删除的rhs。这当然是致命的坑儿了。

跨越这个坑儿:

if (this == &rhs)
    return *this;
delete sb;
sb = new ScrollBar(*rhs.sb);
return *this;

上面这段代码几乎所有的教科书都会这么讲,但是曾经一个arcserver的工程师跟我讲,这样同样存在危险,不是完美的:

试想一下,如果我们delete sb后发生了异常怎么办?这个时候,就会有存在一个没有指向任何东西的指针。所以下面这样写会更好:

Window& Window::operator=(const Window& rhs)
{
    if (this == &rhs)
    return *this;

    ScrollBar *sbOld = sb;
    sb = new ScrollBar(*rhs.sb);
    delete sbOld;
    return *this;
}
时间: 2024-10-22 02:33:33

没有躲过的坑--重载赋值运算符的自我赋值的相关文章

没有躲过的坑--成对使用new和delete时要采取相同的形式

new创建类对象与不new区别: new创建类对象需要指针接收,一处初始化,多处使用 new创建类对象使用完需delete销毁 new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间 new对象指针用途广泛,比如作为函数返回值.函数参数等 而且每个学习C++编程的人都知道成对的使用new和delete,也也就是new申请的内存用delete释放,new []申请的内存由delete []释放. std::string* first_string = new std::string;

第九章:重载赋值运算符中需要注意的两个问题

前言 如果系统自动生成的赋值运算符重载函数不合乎你的要求,那么就应当定制自己的赋值运算符. 然而,定制赋值运算符有两点是非常值得注意的,本文将讲解这两点,让你写出更优质的 =运算符. 第一点:请返回 reference to *this 我们经常使用如 "a=b=c=1" 这种形式的连锁赋值语句,而重载的赋值运算符自然也应当能够这样使用. 因此,在重载运算符函数末尾请写上如这样的语句 return *this; 除了赋值运算符,+=,-=这样的赋值运算符同样需要这样做. 第二点:处理好

重载赋值运算符 && 对象

class CMessage { private: char * m_pMessage; public: void showIt()const { cout << m_pMessage << endl; } //构造函数 CMessage(const char* text="Default message") { cout << "Constructor difinition" << endl; size_t leng

重载赋值运算符中需要注意的两个问题

前言 如果系统自动生成的赋值运算符重载函数不合乎你的要求,那么就应当定制自己的赋值运算符. 然而,定制赋值运算符有两点是非常值得注意的,本文将讲解这两点,让你写出更优质的 =运算符. 第一点:请返回 reference to *this 我们经常使用如 "a=b=c=1" 这种形式的连锁赋值语句,而重载的赋值运算符自然也应当能够这样使用. 因此,在重载运算符函数末尾请写上如这样的语句 return *this; 除了赋值运算符,+=,-=这样的赋值运算符同样需要这样做. 第二点:处理好

没有躲过的坑--指针(内存泄露)

C++被人骂娘最多的就是指针. 夜深人静的时候,拿出几个使用指针容易出现的坑儿.可能我的语言描述有些让人费劲,尽量用代码说话. 通过指向类的NULL指针调用类的成员函数 试图用一个null指针调用类的成员函数,导致崩溃: #include <iostream> using namespace std; class A { int value; public: void dumb() const {cout << "dumb()\n";} void set(int

拷贝构造函数(三)——重载赋值运算符

拷贝构造函数(一)--哲学三连:http://www.cnblogs.com/tenjl-exv/p/8017814.html 拷贝构造函数(二)--深拷贝与浅拷贝:http://www.cnblogs.com/tenjl-exv/p/8017909.html 拷贝构造函数(三)--重载赋值运算符:http://www.cnblogs.com/tenjl-exv/p/8017983.html 关于拷贝函数中的赋值操作符重载  以下讨论中将用到的例子: 1 class CExample 2 { 3

C++ 重载赋值运算符与11选5平台修复

1.C++中重载赋值操作函数应该返回什么? 11选5平台修复(企 娥:217 1793 408)类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如 int x,y,z; x=y=z=15; 赋值行为相当于x=(y=(z=15)),也就是赋值操作应该返回左操作数的引用,因此,为了和内置类型兼容,类中重载赋值操作符应该返回左操作数的引用,即*this,如下类A的重载赋值操作函数的声明, class A{}; A& A::operator=(const

C++进阶--处理拷贝赋值运算符中自赋值的情况

//############################################################################ /* * 处理拷贝赋值运算符=中自赋值的情况 * * * 运算符重载: 利用人们的直觉,减少学习曲线 */ // 自赋值的情况 dog dd; dd = dd; // 看起来很傻 dogs[i] = dogs[j]; // 看起来不怎么傻 /* 实现赋值运算符 */ class collar; class dog { collar* pCo

C++ Primer 学习笔记_60_重载操作符与转换 --赋值、下标、成员訪问操作符

重载操作符与转换 --赋值.下标.成员訪问操作符 一.赋值操作符 类赋值操作符接受类类型形參,通常该形參是对类类型的const引用,但也能够是类类型或对类类型的非const引用.假设未定义这个操作符,则编译器将合成它.类赋值操作符必须是类的成员,以便编译器能够知道是否须要合成一个.并且还能够为一个类定义很多附加的赋值操作符,这些赋值操作符会由于右操作数的不同而构成重载!如string类型: string car("Volks"); car = "Studebaker"