我们先看一个简单的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_ptr
template<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;
};
本文到此为止。