C++知识点43——解引用运算符和箭头运算符的重载及智能指针类的实现

一、概念、

在自定义行为类似指针的类时,需要重载*和->。C++中的智能指针就重载了这两个运算符。->必须是成员函数,*也应该是成员函数。与内置类型保持一致,这两个函数通常都是const的。以为*和->通常不会也不应该改变对象的状态

*运算符的返回值通常都是一个类型的引用(因为类内部的数据不一定非得指向T的对象,也可能指向一个T的派生类对象。如果是这样并且operator*返回的是个T对象,而非一个引用(代表真正的派生类对象),那么,operator*函数便是返回一个错误类型的对象!,也就是导致子类对象转基类对象的切割问题)

->运算符的返回值必须是一个类的指针。因为当自定义类型的operator->被调用时,编译器会将operator->转化为

(obejct.operator->())->member

所以,operator->的返回值必须是一个指针

 

二、示例

通过实现一个智能指针来熟悉这两个运算符的重载,类的整体实现如下

#include <iostream>
#include <memory>

using namespace std;

template <typename T>
class mysmartpointer
{
public:
	mysmartpointer(T *ptr=nullptr):
	 ptr_(ptr),
	 pcount_(new size_t(0))
	{
		cout<<__func__<<endl;
		if (ptr_==nullptr) {//空指针不增加引用计数
			*(this->pcount_)=0;
		}
		else {
			*(this->pcount_)=1;
		}
	}

	mysmartpointer(const mysmartpointer &rval):
	ptr_(rval.ptr_),
	pcount_(rval.pcount_)
	{
		if (ptr_) {//拷贝初始化,如果指针不为空,增加引用计数
			++*pcount_;
		}
		cout<<"mysmartpointer(const mysmartpointer &rval)"<<endl;
	}
	
	mysmartpointer &operator=(const mysmartpointer &rval)
	{
		cout<<__func__<<endl;
		mysmartpointer t(rval);
		this->swap(t);
		--*pcount_;//减少左值的引用计数
		if (*pcount_==0) {//此时如果引用计数为0,那么释放指向的对象和引用计数
			cout<<"delete object when operator="<<endl;
			delete ptr_;
			delete pcount_;
		}
		++*rval.pcount_;//增加右值的引用计数
		return *this;
	}

	T &operator*() const
	{
		cout<<__func__<<endl;
		return *ptr_;//返回指向对象本身
	}

	T *operator->() const
	{
		cout<<__func__<<endl;
		return &this->operator*();//通过调用operator*来实现operator->
	}

	explicit operator bool()
	{
		cout<<__func__<<endl;
		return !(ptr_==nullptr && *pcount_==0);
	}

	void swap(mysmartpointer &t)//交换指针和引用计数
	{
		cout<<__func__<<endl;
		std::swap(this->ptr_, t.ptr_);
		std::swap(this->pcount_, t.pcount_);
	}

	size_t use_count()
	{
		cout<<__func__<<endl;
		return *pcount_;
	}

	~mysmartpointer()
	{
		cout<<__func__<<endl;
		if (--*pcount_==0) {//析构时,--引用计数
			cout<<"delete object"<<endl;
			delete ptr_;
			delete pcount_;
		}
	}
	
private:
	T *ptr_;
	size_t *pcount_;
};

上述代码中,operator->的实现使用过operator*来实现。这两个函数一般只实现一个,另一个直接调用即可

该类中引用计数是采用指针的方式实现的,当对智能指针进行赋值、拷贝时,可以利用指针的特性让两个对象的引用计数同时指向一块内存,共享引用计数

operator=的实现也是采用swap方式,避免重新分配内存,而且可以处理自赋值的情况

 

测试

int main(int argc, char const *argv[])
{
	mysmartpointer<string> spstr1(new string("1234"));
	mysmartpointer<string> spstr2=spstr1;
	cout<<spstr1.use_count()<<endl;
	cout<<spstr2.use_count()<<endl;
	cout<<"------"<<endl;
	mysmartpointer<string> spstr3;
	spstr3=spstr1;
	spstr1=spstr1;
	cout<<spstr3.use_count()<<endl;
	cout<<spstr1.use_count()<<endl;
	cout<<spstr2.use_count()<<endl;
	cout<<spstr1->size()<<endl;
	if (spstr1) {
		cout<<"spstr1 is not nullptr"<<endl;
	}
	return 0;
}

 

参考

《C++ Primer》

《More Effective C++》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值