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

       我们先看一个简单的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;
	};


       本文到此为止。

 

 

      


 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值