C++语法学习笔记三十六:new、delete探秘,智能指针概述、shared_ptr

实例代码:

// 

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>


using namespace std;


class A{
public:
	A(){
		cout << "A()构造函数被调用" << endl;
	}
	~A(){
		cout << "~A()析构函数被调用" << endl;
	}

	int m_b;
};

shared_ptr<int> makes(int value){
	//return new int(value);  不可以,无法把new得到的int * 转换成shared_ptr
	return shared_ptr<int>(new int(value)); //可以,显示的用int* 创建shared_ptr<int>

}



int main()
{
	//一、new/delete探秘
	//(1.1) new ,delete是什么?
	//sizeof(关键字/运算符),不是个函数。
	//new、 delete(关键字/运算符),不是个函数
	// malloc/free (主要用于C语言编程中),而new/delete用于C++编程,这两对都用于动态的在堆中分配/释放内存
	//new / delete比malloc / free干的事情更多;

	A* pa = new A(); // 构造函数被调用
	delete pa; // 析构函数被调用
	//new / delete 具备对堆上所分配内存进行初始化/ 释放(反初始化)的能力,而这些能力是malloc/free所不具备的


	//(1.2) operator new()和operator delete()

	int *pi = new int;
	delete pi;

	//operator new() 和 operator delete() 函数
	//(1.2.1)new 干了两个事情:
	//	a)分配内存(通过operator new())来分配内存).
	//  b)调用构造函数来初始化内存.

	void *myorgpoint = operator new(100); //分配100字节,一般没人这么干

	//(1.2.2) delete也干了两个事情:
	//   a). 调用析构函数
	//   b). 释放内存(调用operator delete()来释放内存)


	//(1.3) 基本new如何记录分配的内存大小供delete使用
	//不同编译器new内部有不同的实现方式:
	int *p = new int; // 4字节
	delete p; //删除的时候,编译器怎么知道要回收的是4字节,new内部有记录机制,记录了分配出去多少内存。


	//(1.4) 申请和释放一个数组
	//int *p2 = new int(100); // 分配4字节,给int = 100;
	//int *p3 = new int[2]; // int 数组, 有两个元素,泄漏8字节
	//A a;
	//int ilen = sizeof(a); //类对象肯定有地址,你就得至少占1个字节的地方

	//A *pA = new A();  // 泄漏1字节
	A *pA = new A[2](); // 这里泄漏6字节,而不是2字节,多出来4字节;这四个字节用来干嘛的?
	int *p4 = new int[2]; //int 数组,有两个元素,泄漏8个字节,没有多出四个字节来呢?
	//疑问:为什么动态给类型A分配内存对象数组时多出来4个字节,而给内置类型int动态分配内存对象数组时并没有多出来4字节

	//new[] 应该用delete[]释放
	int *p5 = new int[3];  // int 内置类型
	//delete p5; //没有用[],似乎也可以直接释放p这个int数组,没有发生内存泄漏;
	delete []p5; // 这种释放方法才是规范的,绝对没有问题的;


	A *pA1 = new A[2](); //泄漏6字节,2个字节代表类对象数组占用的,额外4字节我们纳闷这4字节从哪儿来?
	//delete pA1; // 系统报告异常,为什么报异常呢?
	delete[] pA1; // 这种写法是最规范的,是没问题的;  A: 类类型


	//(1.5) 为什么new / delete 、new[]/delete[]要配对使用?
	//内置类型比如int不需要调用析构函数,所以new[] 的时候系统并没有多分配出4字节;
	//对于int类型,new[] ,delete p或者delete []p ,效果一样;

	//结论:如果一个对象(内置对象比如int float, 包括类对象A),使用new[]来分配内存,却用单独的delete(而不是
	//delete[]来释放内存,那么这个对象需要满足的条件是:对象的类型要么是内置类型或者无自定义的析构函数的类类型。)
	// 
	//A *pA2 = new A[2](); //如果没析构函数,这里就分配了2个字节。
	//delete pA2; //为什么字节一提供析构函数,不用delete[]来释放new[]出来的内存就报异常呢?
	//a). 调用一次A的析构函数而不是2次,至少是表示有内存泄漏;
	//b). 调用operator delete(pA2);释放内存。

	//0x00000012; 0x00000016开始的内存;
	/*A *pA3 = new A();
	if (...){
		return;
	}
	// ...
	delete[]pA3;
	pA3 ...
	*/

	// 结论: new/delete, new[]/delete[] 要配对使用;否则程序出错,自食恶果;


	//二、智能指针总述

	int *p11 = new int();
	int *q11 = p11;
	int *r11 = q11; //只有p11 q11 r11 都不在使用了的时候,才能释放掉这段内存。

	//new /delete的写法要非常小心,防止早早的释放,也防止忘记释放,总之:用好并不容易
	//p 裸指针:直接用new 返回的指针,这种指针,强大,灵活,但是开发者全程负责维护,一个不小心,就容易用错,一旦用错,造成
	//智能指针: 解决裸指针可能出现的各种问题;
	//智能指针,就理解成对“裸指针”进行了包装,给裸指针外边包了一层;包装后为我们带来优点;
	// 最突出的优点: 智能指针能够“自动释放所指向的对象内存”,大家再也不用担心自己new出来的内存忘记释放了;
	//建议优先选择智能指针,使用智能指针的程序更容易编写和调试;

	//C++ 标准库有四种智能指针:std::
	// a) auto_ptr (C++ 98);   unique_ptr (C++ 11);  shared_ptr (C++ 11); weak_ptr(C++ 11); 

	//帮助我们进行动态分配对象(new出来的对象)的生命周期的管理。能够有效防止内存泄漏;
	//目前auto_ptr已经完全被unique_ptr取代,所以大家不要再使用auto_ptr;C++ 11标准中反对使用auto_ptr(弃用)
	//这三种智能指针都是类模板,我们可以将new获得地址赋给他们;
	// a)shared_ptr : 共享式指针。多个指针指向同一个对象,最后一个指针被销毁时,这个对象会被释放。
	//   weak_ptr 是辅助shared_ptr工作的;
	// b) unique_ptr : 独占式指针;同一个时间内,只有一个指针能够指向该对象。
	//   当然,该对象的所有权还是可以移交出去的;
	// 你忘记delete 的时候,智能指针帮组你delete,或者说,你压根就不再需要自己delete;智能指针的本分(帮助你delete)


	//三、shared_ptr基础
	//共享所有权,不是被一个shared_ptr拥有,而是被多个shared_ptr之间互相协作;shared_ptr有额外开销;
	//工作原理:引用计数,每个shared_ptr的拷贝都指向相同的内存。
	//  所以,只有最后一个指向该内存(对象)的shared_ptr指针不需要再指向该对象时,那么这个shared_ptr才会去析构所指向的对象
	//最后一个指向该内存对象的shared_ptr在什么情况下会释放该对象(shared_ptr所指向的对象)呢?
	// a) 这个shared_ptr被析构的时候;
	// b)这个shared_ptr指向其他的对象时;
	// 垃圾回收机制;我们从此不用担心对象何时被delete;
	// 类模板,用到<>, <>里,就是指针可以指向的类型,后边再跟智能指针名;
	// 格式: shared_ptr<指向的类型> 智能指针名:

	//(3.1)   常规初始化(shared_ptr和new配合)
	shared_ptr<int> pi11(new int(100)); // pi指向一个值为100 的int型数据
	//shared_ptr<int> pi211 = new int(200); // 不行,智能指针是explicit, 不可以进行隐式类型转换。必须用直接初始化形式;(“=” 一般都是隐式转换)
	shared_ptr<int> pi311 = makes(130);

	//裸指针可以初始化shared_ptr, 但不推荐。智能指针和裸指针不要穿插用;
	//int *pi22 = new int;
	//shared_ptr<int> pl(pi22);

	//shared_ptr<int> pl33(new int);

	//(3.2)   make_shared函数: 标准库里的函数模板,安全、搞笑的分配和使用shared_ptr;
	//它能够在动态内存(堆)中分配并初始化一个对象,然后返回指向此对象的shared_ptr;
	shared_ptr<int> p7 = make_shared<int>(100); //这个shared_ptr指向一个值为100的整形内存,有点类似int *pi = new int(100)
	shared_ptr<string> p8 = make_shared<string>(5, 'a'); // 5个字符a生成的字符串。
	// 类似于 string mystr(5, 'a');
	shared_ptr<int> p9 = make_shared<int>(); // p4指向一个int, int里保存的值是0 (值初始化)
	p9 = make_shared<int>(400); // p4 指向一个新int, int 里保存的是400; p4 首先释放刚才指向的值为0的内存,然后指向这个值为400的内存
	auto p10 = make_shared<string>(5, 'a'); // 用auto比较简单


	system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值