c++11学习笔记:动态内存

(1)在c++中,动态内存的管理是通过一对运算符来完成的。new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化。delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
(2)动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的,有时我们会忘记释放内存,在这种情况下会产生内存泄露。有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针。
(3)为了更容易安全使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责移动释放所指向非对象。
(4)新标准库提供的这两种智能指针的区别在于管理底层指针的方式,shared_ptr允许多个指针指向同一个对象,unique_ptr则独占所指向的对象,标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这3种类型都定义在memory头文件里面。
(5)类似vector,智能指针也是模板,因此,当我们创建一个智能指针的时候,必须提供额外的信息,指针可以指向的类型。和vector一样,我们在尖括号内给出类型,之后是所定义的这种智能指针的名字。

shared_ptr<string> p1;
shared_ptr<list<int>> p2;//可以指向int的list

(6)智能指针的使用方式和普通指针类似,解引用一个智能指针返回它指向非对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空。
如果p1指向一个空string,解引用p1,将一个新值赋予string。

if(p1 && p1->empty())
    *p1="hi";

(7)最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。这个函数在动态内存中分配一个对象并初始化它,返回指向此对象的

shared_ptr。shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4=make_shared<string>(10, '9');
shared_ptr<int> p5 = make_shared<int>();
//通常用auto定义一个对象来保存make_shared的结果,这种方式较为简单。
auto p6 = make_shared<vector<string>>();

(8)当进行拷贝或赋值操作的时候,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象。

//p指向的对象只有p一个引用者
auto p = make_shared<int>(42);
//p和q指向相同对象,此对象有两个引用者
auto q(p);

(9)在学习下一章之前,除非使用智能指针来管理内存,否则不要分配动态内存。
在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而且返回一个返回该对象的指针。

int *pi = new int;

pi指向一个动态分配未初始化的无名对象。
默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或组合类型的对象的值将是未定义的,而类类型对象将用默认构造函数进行初始化。

string *ps = new string;
int *pi = new int;
int *pi = new int(1024);
string *ps = new string(10, '9');
vector<int> *pv = new vector<int>(0,1,2,3);
auto p1 = new auto(obj);
const int *pci = new const int(1035);
const string *pcs = new const string;

(10)delete p;
p必须指向一个动态分配对象或一个空指针

int i, *pi1 = &i, *pi2 = nullptr;
double *pd = new double(33), *pd2 = pd;
delete i;//错误,i不是一个指针
delete pi1;//未定义,pi1指向一个局部变量
delete pd;//正确
delete pd2;//未定义,pd2指向内存已被释放
delete pi2://释放空指针正确。

动态数组:

 

复制代码
int *pia = new int[10];//10个没有初始化的int
int *pia2 = new int[10]();//10个初始化值为0的int
string *psa = new string[10];//10个空string
string *psa2 = new string[10]();
//在新标准中还可以提供一个元素初始化器的花括号列表
int *pia3 = new int[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
string *psa3 = new string[10]{"sd", ...};

typedef int arrT[42];
int *p = new arrT;
delete [] p;//方括号是必须的,因为当时我们分配的是一个数组
复制代码

 

(11)如果我们不初始化一个智能指针,它就会被初始化为一个空指针,我们可以使用new返回的指针来初始化智能指针。

shared_ptr<double> p1;
shared_ptr<int> p2(new int(42));
shared_ptr<int> p3 = new int(20);
//p3是错误的,必须使用直接初始化的形式

(12)和shared_ptr不同,没有类似make_shared的标准库函数返回一个unique_ptr,当我们定义一个unique_ptr的时候,需要将其绑定到一个new返回的指针上。类似share_ptr,初始化unique_ptr必须采用直接初始化形式。

unique_ptr<double> p1;
//可以指向一个double的unique_ptr
unique_ptr<int> p2(new int(42));

由于一个unique_ptr拥有它指向非对象,因此unique_ptr不支持普通的拷贝或赋值操作
(13)虽然我们不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个

posted @   花与不易  阅读(83)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示