c++ primer 12.1.2 - 12.1.4直接管理内存(new和delete笔记以及shared_ptr)

  1. new在c++11中可以使用列表初始化
std::vector<int>* vec = new std::vector<int>{1, 2, 3, 4, 5, 6};
  1. 对于内置类型,默认初始化和值初始化可能不同
int* num = new int; // 默认初始化 *num的值不确定
int* num1 = new int(); // 值初始化 *num1的值被初始化为0
  1. new也可以使用auto来推断类型,但括号内只能有单一参数
auto p1 = new auto(obj1); // p1所指向的类型和obj1类型相同 并且用obj1来初始化该对象
auto p2 = new auto(a, b, c); // 无法初始化,括号中有多个参数
  1. 定位new
    new不能分配所要求的空间时,new会抛出异常std::bad_alloc,如果不想让new在此时抛出异常,可以为new传入nothrow参数
int* p = new (nothrow) int; // new失败时,会返回一个空指针,不会抛出异常
  1. delete一个nullptr指针是被允许的
  2. 可以new const修饰的指针
    // ptr2指针本身的值不能被改变
	int* const ptr2 = new int();
	*ptr2 = 1;

	// 无法通过ptr3修改到所指向对象的值
	const int* ptr3 = new int(1);
  1. 定义shared_ptr的其他方法
	// 定义std::share_ptr的其他方法
	auto q = new int();
	std::shared_ptr<int> p(q); // p接管q所指向的内存

	std::unique_ptr<int> u(new int());
	std::shared_ptr<int> p(u); // p接管unique_ptr管理的内存 并将unique_ptr制空

	std::shared_ptr<int> p(q, d); // d为可调用对象 用于替代delete操作(shared_ptr默认使用delete来释放所管理的内存)
  1. 不要将std::shared_ptr和普通指针混用
    使用一个普通指针初始化std::shared_ptr后,该指针指向的内存就交给std::shared_ptr来管理了,此时,不应该再使用这个普通指针了,因此推荐使用std::make_shared来初始化一个std::shared_ptr
void fun(std::shared_ptr<int> ptr)
{
	std::cout << *ptr << std::endl;
}

int main()
{
	int* p = new int(10); // 普通指针
	
	// 此处产生了一个临时std::shared_ptr<int>对象 该对象同样管理着这块动态内存
	fun(std::shared_ptr<int>(p));
	// 一旦fun执行完 将会导致std::shared_ptr释放掉p指向的内存
	// 即此处std::shared_ptr<int>临时对象的计数为1 在fun函数中由于形参的存在计数变为2
    // 离开fun函数后形参离开作用域结束计数变为1 该表达式结束后临时对象析构 计数器变为0 这块内存被delete掉

	// shared_ptr导致p指向的内存已经被释放 该操作会出问题
	std::cout << *p << std::endl;
	
	return 0;
}

因此使用一个内置指针来访问一个std::shared_ptr中所管理的内存是危险的,因为不知道该std::shared_ptr什么时候会释放掉这块内存。
9. 谨慎使用std::shared_ptr的get函数
get函数会将所管理的指针交给其他代码,该函数被设计的原因是,用于向一些无法使用智能指针的代码传递普通指针。在使用时要保证这部分代码不会delete掉指针。
注意:永远不要用get来初始化另外一个智能指针

int main()
{
	std::shared_ptr<int> p(new int(10)); // p的计数器为1
	{
		std::shared_ptr<int> q(p.get()); // ptr的计数器为1
	}
	// q计数器变为0 所管理的内存被析构

    // p管理的内存被q释放 使用p将会出现错误
	std::cout << *p << std::endl;

	return 0;
}

10.share_pt的删除器
哑类:没有任何数据成员也没有虚函数的类,由于哑类不包含任何数据成员,它的对象在内存中不需要占用空间,因此对象的尺寸为0。为了处理这种特殊情况,C++在处理哑类时会增加一个哑成员,使得对象的尺寸至少为1,从而避免了一些非法操作,如取地址或比较地址等‌。该类用于简单的占位符对象来满足接口要求等。
删除器:shared_ptr在构造时可以传递一个函数作为删除器,该shared_ptr在离开作用域析构时,调用该删除器代替delete操作

对于一些c接口,会有申请资源和释放资源两步,可以使用share_ptr来管理资源描述符来避免忘记释放资源,或者抛出异常导致无法运行道释放资源的代码,例如如下代码:

#include <iostream>
#include <memory>
#include <string>
#include "StrBlob.h"
#include <stdio.h>

void deleteFun(FILE* file)
{
	if (file) {
		fclose(file);
		file = nullptr;
		std::cout << "Close file" << std::endl;
	}
}

int main()
{
	FILE* file = fopen("./a.txt", "w");
	std::shared_ptr<FILE> filePtr(file, deleteFun); // 在filePtr析构时 会关闭已打开的文件 避免资源未释放

    // 在此处即使执行一些操作 引发了异常 也不会导致file未释放

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值