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