Effective C++条款11解读: 在operator=中处理“自我赋值”------顺便给出string类的Big Three

来源:互联网 发布:阿里云市场镜像安全吗 编辑:程序博客网 时间:2024/04/29 11:17

       我们先看一个简单的string程序:

#include <iostream>using namespace std;class TaogeString{private:char *m_p;public:TaogeString(char *p = NULL){if(NULL == p){m_p = new char[1];m_p[0] = '\0';}else{int len = strlen(p);m_p = new char[len + 1];strcpy(m_p, p);}}TaogeString(const TaogeString &a){int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);}TaogeString& operator=(const TaogeString &a) {delete m_p;int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);return *this;}~TaogeString(){delete []m_p;m_p = NULL;}void print(){cout << m_p << endl;}};int main(){TaogeString a("good");TaogeString b("");b = a;b.print();return 0;}
      运行一下, 结果为:

good


      其实, 上面程序是有问题的, 不信, 请看:

#include <iostream>using namespace std;class TaogeString{private:char *m_p;public:TaogeString(char *p = NULL){if(NULL == p){m_p = new char[1];m_p[0] = '\0';}else{int len = strlen(p);m_p = new char[len + 1];strcpy(m_p, p);}}TaogeString(const TaogeString &a){int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);}TaogeString& operator=(const TaogeString &a) {delete m_p;int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);return *this;}~TaogeString(){delete []m_p;m_p = NULL;}void print(){cout << m_p << endl;}};int main(){TaogeString a("good");a = a; // 自我赋值a.print();return 0;}
       结果, a对应的是一个垃圾值? 为什么呢? 我们看看operator=函数就清楚了, 没有处理自我赋值, 导致a中指针指向的堆被释放了。 有的朋友可能说: 谁他妈无聊去自我赋值啊? 其实, 自我赋值的情况还是很普遍的, 比如x[i] = x[j], 当i和j相等的时候, 就自然而然是自我赋值了。 所以, 为了程序的健壮性, 必须考虑自我赋值。 上面的程序改为:

#include <iostream>using namespace std;class TaogeString{private:char *m_p;public:TaogeString(char *p = NULL){if(NULL == p){m_p = new char[1];m_p[0] = '\0';}else{int len = strlen(p);m_p = new char[len + 1];strcpy(m_p, p);}}TaogeString(const TaogeString &a){int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);}TaogeString& operator=(const TaogeString &a) {if(&a == this) // 处理自我赋值{return *this;}delete m_p;int len = strlen(a.m_p);m_p = new char[len + 1];strcpy(m_p, a.m_p);return *this;}~TaogeString(){delete []m_p;m_p = NULL;}void print(){cout << m_p << endl;}};int main(){TaogeString a("good");a = a; // 自我赋值a.print();return 0;}
       结果为:

good


      这样就好了。 


      如果大家熟悉STL源码, 就可以到处见到这种自我赋值的防护机制。 之前, 我们剖析过auto_ptr的源码, 其中也有自我赋值的处理, 下面, 我们再次把这个源码拿过来, 放在下面, 作为本文的终结,让我们再次看看微软式的风骚代码:

// TEMPLATE CLASS auto_ptrtemplate<class _Ty>class auto_ptr {public:typedef _Ty element_type;explicit auto_ptr(_Ty *_P = 0) _THROW0(): _Owns(_P != 0), _Ptr(_P) {}auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0(): _Owns(_Y._Owns), _Ptr(_Y.release()) {}auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0(){if (this != &_Y)  {if (_Ptr != _Y.get()){if (_Owns)delete _Ptr;_Owns = _Y._Owns; }else if (_Y._Owns)_Owns = true;_Ptr = _Y.release(); }return (*this); }~auto_ptr(){if (_Owns)delete _Ptr; }_Ty& operator*() const _THROW0(){return (*get()); }_Ty *operator->() const _THROW0(){return (get()); }_Ty *get() const _THROW0(){return (_Ptr); }_Ty *release() const _THROW0(){((auto_ptr<_Ty> *)this)->_Owns = false;return (_Ptr); }private:bool _Owns;_Ty *_Ptr;};

       本文到此为止。


      



0 0
原创粉丝点击