面试可能会问六:智能指针

先看一下百度百科的解释:

指针指针

当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。

智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数器跟踪该类有多少个对象的指针指向同一对象。

实现原理:

每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。

个人建议:好好读读百度百科这个版本,解释挺好的。此处不再赘述。

个人提供一个简单版的智能指针实现。

运算符重载的角度来看一下。

#pragma once

#include<iostream>
using namespace std;

class Person
{
public :
	Person(int age);
	void showAge();
	~Person();

private :
	int mAge;
};
#include "Person.h"


Person::Person(int age)
{
	this->mAge = age;
}

void Person::showAge()
{
	cout << "年龄为:" << this->mAge << endl;
}

Person::~Person()
{
	cout << "析构函数被调用。" << endl;
}
#include "Person.h"


void test01()
{
	Person p1(10);  //建立在栈中,函数结束由编译器自动销毁。

}


int main()
{
	test01();

	return EXIT_SUCCESS;
}

如果我们把对象建立在栈上,函数在运行结束后,编译器自动回收。

如果我们把对象建立在堆中。new一个指针变量出来。(所有new出来的对象,都返回该类型的指针。)开辟在堆中,就需要我们自己手动去释放。

void test01()
{
	//Person p1(10);  //建立在栈中,函数结束由编译器自动销毁。
	Person *p1 = new Person(10);   // new返回指针类型的对象。
	delete p1;  // 必须手动释放。
}

如果我们的代码有几百行,那么我们很容易遗漏这样的释放。所以在C++11中,有了一个新的特性:指针指针。

用来:用来托管自定义类型的对象,让对象自动的释放。

如何实现呢,我们自己实现一个:写一个智能指针类,就只是管理一个属性:也就是这个自定义类型的指针。Person*。

为了管理这个指针,在构造时,就需要将这个指针传输到构造函数中去,然后整个类,维护这个指针。

class SmartPointer
{
public:
	SmartPointer(Person* person)
	{
		this->person = person;
	}
	~SmartPointer()
	{
		if (this->person != NULL)
		{
			delete this->person;
			this->person = NULL;
		}
	}
private:
	Person* person;
};

如何实现呢?

void test02()
{
	SmartPointer sp(new Person(10));
}

如此即实现了指针堆中创建,又实现了在栈中由编译器管理。继而实现自动释放。省去了我们忘记delete的烦恼。栈中变量sp在自动释放时,执行自己的析构函数,自己的析构函数,管理着我们要被托管的指针。进而实现了指针的自动释放。

上面是自动释放的实现,还有一个问题,在我们被托管类指针中,要调用showAge方法,此时用智能指针是无法无法实现的。即:sp->showAge()无法实现。

如果要调用这个方法,我们可以把我们的->运算符重载

Person* operator->()
{
	return this->person;
}

此时在sp->运算时,返回的是被托管的指针。只要我们把指针返回,即可调用原来的方法。

如果要实现调用showAge。那么需要sp->->showAge()即可,但是编译器看着两个->觉得多余,这边给我们做了自动的编译器优化

此外,我们使用指针,还有一种用法是解引用:(*p).showAge();

Person& operator*()  // 返回值是对对象本体的引用,不是Person。
{
	return *this->person;
}
void test02()
{
	SmartPointer sp(new Person(10));
	sp->showAge();
	(*sp).showAge();
}

这就有点为了讲解运算符重载为了为之而为之了。 但是也基本讲明了一种实现方式和原理。当然新特性中的智能指针没有那么简单哈。


其实直接友元类也可以实现对成员函数的调用。

#pragma once

#include<iostream>
using namespace std;
class SmartPointer;

class Person
{
public :
	friend class SmartPointer;
	Person(int age);
	void showAge();
	~Person();

private :
	int mAge;
};

声明被托管指针时:可以将其智能指针作为友元类。

然后再友类中直接调用即可。

#include "Person.h"

class SmartPointer
{
public:
	SmartPointer(Person* person)
	{
		this->person = person;
	}
#if 0
	Person* operator->()
	{
		return this->person;
	}

	Person& operator*()  // 返回值是对对象本体的引用,不是Person。
	{
		return *this->person;
	}
#endif 
	~SmartPointer()
	{
		if (this->person != NULL)
		{
			delete this->person;
			this->person = NULL;
		}
		cout << "智能指针被释放。" << endl;
	}

	void showAge()
	{
		this->person->showAge();
	}

private:
	Person* person;
};

void test01()
{
	//Person p1(10);  //建立在栈中,函数结束由编译器自动销毁。
	Person *p1 = new Person(10);   // new返回指针类型的对象。
	delete p1;  // 必须手动释放。
}

void test02()
{
	SmartPointer sp(new Person(10));
	//sp->showAge();
	//(*sp).showAge();
	sp.showAge();
}

int main()
{
	//test01();
	test02();

	return EXIT_SUCCESS;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值