C++指针和引用、智能指针

指针和引用的区别

引用是C++里面有C里面没有的,它们都能间接地指代其他对象,但引用比指针更安全
指针和引用的区别:
1.存在空指针(不指向任一对象),但不存在空引用(必须初始化),引用总是要指代一个对象(且必须为左值),所以使用引用比指针更高效,指针在使用前得检查其是否有效(为空)。
2.指针可以重新被赋值指向另一个对象,但引用总是指向其初始化指向的对象。

void TEST_REFERENCE() {
	int a = 1;
	int& b = a;
	//int& b;		//错误,必须初始化
	//int& b = 0;	//错误,必须用左值初始化
	a = 2;
	std::cout << a << b;	// 22

	int tmp = 3;
	b = tmp;
	std::cout << a << b;	//33
}

使用指针的情况:
1.有可能不指向任何对象,这种情况下可置为空;
2.在不同的情况需要指向不同的对象。
其他情况应使用引用,更安全更高效,总是指向一个对象不变。

未初始化的指针的值是随机的。使用未初始化的指针(野指针)会导致各种问题。所以指针定义时应当初始化,要么指向合法内存(用其他指针赋值或new分配内存),要么赋值为空。即使不指向任何东西,也应该赋值为空指针。在C++11中引入了nullptr作为空指针。

int* p1 = nullptr;	// >=C++11
int* p2{};			// 同上

int* p3 = 0;			// 不推荐,容易类型混淆
int* p4 = NULL;

指针使用不当导致的问题:
1.野指针。指针未被初始化,或者指针释放后仍去访问那块内存(正常返回但结果错误)。new和delete要对应,并且指针delete释放后应置为空

2.内存泄露。已经分配内存的指针未释放就指向其他内存,导致原先分配的内存无法被访问。

3.内存越界。

void TEST1() {	// 野指针 
	int *ptr{new int};	//分配内存 
	
	*ptr = 1;
	cout<<*ptr<<endl;
	
	//delete ptr;		
	//cout<<*ptr<<endl;	//返回0,但结果错误 

	//delete ptr;	
	//ptr = nullptr;	//推荐	
	//cout<<*ptr<<endl;	//引发异常,返回非0 
}

void TEST2() {	// 内存泄露 
	int* a = new int[5];
	a = new int[10];	// 内存泄露,丢失20B
	
	/*
	// 正确做法
	int* a = new int[5];
	delete[]a;
	a = nullptr;
	a = new int[15];
	a[14] = 2;
	std::cout << a[14];
	*/
}

void TEST3 (){	//  
	int *a = new int[5]{};

	cout<<a[1]; 
	cout<<a[6];		// 越界 
}

注意以上代码只为突出问题,并未在意其他细节,例如没有delete。

智能指针

智能指针是C++11的新特性。三种智能指针的定义都在头文件中定义?
智能指针都是类模板,其析构函数用delete释放内存,这也使得智能指针的赋值得是new出来的。

int tmp = 3;
smart_ptr<int>a{&tmp};	//错

int *tmp = new int(3);
smart_ptr<int>a{tmp};	//对

独占指针unique_ptr

1.独占指针存在析构函数,由析构函数释放内存(通过delete),所以独占指针必须赋值(初始化)为动态分配得到的内存。不然普通内存不是new出来的,也没有delete,自然析构函数出错。
2.独占指针不能直接赋值给裸指针。
3.独占指针不能赋值给另一个独占指针,但可以被移动。
总之,独占指针,独占独占,意思就是只有一个指针占用这块内存,不允许其他指针指向这块内存(即不能将独占指针赋值给其他指针,否则就成共享指针了)。但可以通过move语义将独占指针的内存所有权转移至另一独占指针,此时原独占指针为空。

void TEST_UNIQUE_POINTER() {
	std::unique_ptr<int>a{ new int };
	//std::unique_ptr<int>a = nullptr;	//错误
	// std::unique_ptr<int>a = new int;	//错误
	//a = nullptr;
	*a = 7;
	std::cout << *a << std::endl;

	//int tmp = 3;
	//std::unique_ptr<int>b{ &tmp };	//编译通过,单步执行该语句也不报错,当b消失时调用其析构函数才报错

	int* tmp = new int;
	*tmp = 3;
	std::unique_ptr<int>b{ tmp };
	
	//int* c = a;		//错误。不能直接将独占指针赋值给裸指针
	int* c = a.get();
	std::cout << *c << std::endl;	//正确赋值

	//std::unique_ptr<int>d{ a };	//独占指针也不能赋值给独占指针,只能移动
	//std::unique_ptr<int>d = a;

	std::unique_ptr<int>a1{ move(a) }, a2;	//内存所有权转移至a1,a为nullptr
	a2 = move(a1);							//内存所有权转移至a2,a1为nullptr
	if (nullptr==a && nullptr==a1)	// true
		std::cout << "a=nullptr, a1=nullptr"<<std::endl;
}//函数结束后,a2的析构函数会释放内存

共享指针shared_ptr

多个指针指向同一块内存。当所有shared_ptr不再引用这一内存,内存就被自动释放。
shares_ptr有一个引用计数,代表指向这一内存的共享指针的个数,可用use_count() 获取,当引用计数为0时才delete释放内存,避免了重复释放引发异常。
和unique_ptr相比,shared_ptr可以随意被复制。
推荐使用make_shared创建shared_ptr

void TEST_SHARED_POINTER() {
	int* tmp = new int(2);
	std::shared_ptr<int>a{ tmp };
	//std::shared_ptr<int>a = tmp;	错
	std::cout << *a << std::endl;	//2
	//int tmp = 3;
	//std::shared_ptr<int>b{ &tmp };	//错

	std::shared_ptr<int>c = a;	//随意复制
	std::cout << a.use_count() << c.use_count() << std::endl;	//22

	std::shared_ptr<int>d = std::make_shared<int>();	//初始值为0
	std::shared_ptr<int>e = std::make_shared<int>(1);	//初始值为1
}//函数结束后,析构函数会释放内存

弱指针weak_ptr

shared_ptr存在循环引用问题,导致内存无法释放。weak_ptr可以打破循环引用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值