第12章 动态内存

全局对象:启动时分配,结束时销毁

局部对象:程序块内分配,程序块外销毁

static对象:第一次使用分配,结束时销毁

动态内存使用new来分配对象,使用delete销毁对象

12.1两种智能指针

#include<memory>

shared_ptr: 多个指针可以指向同一个对象

unique_ptr: 独占指向的对象

weak_ptr: 一个伴随类,指向shared_ptr管理的对象,是弱引用

智能指针也是模板,定义时需要指明类型

shared_ptr<string> p1;

shared_ptr<list<int>> p2;

默认初始化为空指针


shared_ptr和unique_ptr都支持的操作


unique_ptr<T> up

shared_ptr<T> sp


空智能指针,指向类型为T的对象


p


作为一个条件判断,指向一个对象则为true


*p


解引用,获得指向的对象


p->item


等价于(*p).item


p.get()


返回p中保存的指针


swap(p, q)

p.swap(q)


交换p和q中的指针


shared_ptr独有的操作


make_shared<T>(args)


返回一个shared_ptr,使用args初始化T的对象


shared_ptr<T> p(q)


p是q的拷贝,指向同一个对象,q中计数器递增


p=q


递减p中引用计数,递增q中引用计数


p.unique()


如果p.use_count()为1,返回true


p.use_count()


返回p共享对象的智能指针的数量,很慢,用于调试

使用动态内存的三种原因

  1. 程序不知道需要使用多少对象
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象间共享数据

12.1.2直接管理内存

int *ptr = new int; //默认初始化,值未定义
int *ptr1 = new int();//值初始化为0
int *ptr2 = new int(1024);
const int *ptr3 = new const int(1024);
int *ptr4 = new (nothrow) int(1024);//分配失败,不抛出bad_alloc异常,而是返回空指针
string *str = new string; //默认初始化为空string
string *str1 = new string();//值初始化为空string
string *str2 = new string("string");
vector<int> *pv = new vector<int>{ 1, 2, 3, 4, 5 };
auto p = new auto("123");//为const char**
auto p = new auto(string("123"));//为string*

int i, *pi1 = &i, *pi2 = nullptr;
double *pd = new double(33), *pd2 = pd;
delete i;  // 错误,i不是指针
delete pi1; // 未定义,pil是一个局部变量
delete pd;  // 成功
delete pd2; // 未定义,pd2已经被释放
delete pi2; // 成功,释放了一个为空的指针

释放内存之后,指针变成了悬空指针(dangling pointer),通常仍然指向原来的内存地址,如果之后再次delete,会破坏自由空间内存,通常需要重新赋予nullptr。

12.1.3结合使用shared_ptr和new

shared_ptr<int> p2 = new int(42);// 错误int*不能隐式转换成智能指针
shared_ptr<int> p2(new int(42));// 正确,因为构造函数是explicit,上边才不成立
int* q = new int(10);
shared_ptr<int> p(q, [](int* p) {cout << *p; delete p; });// 自定义释放内存的方法

不建议结合使用

其他操作

shared_ptr<int> p(new int(9));
int *pi = p.get();// 得到内置指针
if (!p.unique())//不是唯一引用
    p.reset(new int(*p + 1));//改变p的指向,不影响其他引用的值
*p = *p + 1;//唯一引用,直接改变也不影响其他的了

12.1.4智能指针与.Net using

void f(destination &d)
{
    connection c = connect(&d);
    //保证在程序结束后释放c
    shared_ptr<connection> p(&c, [](auto c) {delete c; });
    ...
}

12.1.5独占智能指针unique_ptr

unique_ptr不能进行赋值、拷贝操作

unique_ptr<int> u;
u = nullptr;//释放u的对象,并置空
u.release();//释放u的对象控制,并返回内置指针,置空u
u.reset();//释放u的对象
u.reset(q);//指向q,释放u的对象

可以拷贝和返回一个将要被销毁的unique_ptr例如参数返回时的拷贝,这其实是一种特殊的拷贝(13.6.2)。

自定义删除器需要在定义时指明类型,这与shared_ptr作为参数不同。

unique_ptr<int, decltype(process)*> u(new int(10), process);

12.1.6弱智能指针weak_ptr

weak_ptr将会绑定到一个shared_ptr,它不会改变shared_ptr的引用计数。

弱智能指针需要用shared_ptr对象初始化。

shared_ptr<int> u1(new int(50));
weak_ptr<int> w = u1;
w.reset();// 置空w
w.use_count();//共享shared_ptr的数量
w.expired();//user_count为0,返回true,否则为false
w.lock();//返回对应的一个shared_ptr对象,如果expired为true,则返回的是空的对象
if (shared_ptr<int> u = w.lock())//可以判断并得到shared_ptr

12.2动态数组

最好使用vector、string等其他标准库中的容器,这些标准库可以使用默认版本的拷贝、赋值和析构操作,而使用动态数组,就需要自己考虑了。

12.2.1数组的new

int *pia = new int[10];//10个未初始化
int *pia1 = new int[10]();//10个值初始化为0
int *pia2 = new int[10]{ 1,2,3 };//前三个为1,2,3,其他的为0
  1. 需要注意的是,分配的内存空间并不是数组类型空间,而仅仅是内存空间,并且返回一个首地址。
  2. 使用new分配的对象,执行默认初始化。

释放时需要用到

delete[] pia;

对于释放时delete中如何知道内存中的大小,一般的编译器是通过在分配的动态数组前记录分配的内存的大小,然后释放的时候读取记录进行释放。

使用智能指针管理动态数组

unique_ptr<int[]> u(new int[10]);
cout << u[10] << endl;
u.release();//可以自动调用delete []

shared_ptr<int> sp(new int[10], [](int*p) {delete[] p; });//需要自定义销毁函数
sp.reset();//使用自定义销毁函数

shared_ptr不直接支持动态数组管理,所以也不支持下标运算和指针的算术运算,需要使用时,必须使用get获取内置指针。


allocator<T> a


定义一个为T类型对象分配内存的allocator对象


a.allocate(n)


为n个T类型对象分配内存


a.deallocate(p, n)


收回为n个T类型对象分配的内存


a.construct(p, args)


在p指向的位置构造T对象(需要一个一个构造)


a.destroy(p)


销毁p指向位置的T对象(需要一个一个销毁)

int count = 10;
allocator<string> a;
//分配内存
string* p = a.allocate(count);
for (int i = 0; i < count; i++)
    a.construct(p + i);//构造对象
for (int i = 0; i < count; i++)
    a.destroy(p + i);//销毁对象
//收回内存
a.deallocate(p, count);

uninitialized_copy(b,e,b2)


从迭代器b到e的范围中的对象,内拷贝到b2内存中


uninitialized_copy_n(b,n,b2)


从迭代器b开始的n个元素拷贝到b2内存中


uninitialized_fill(b,e,t)


在b到e的范围中创建t的拷贝


uninitialized_fill_n(b,n,t)


在b开始的n个元素内存中,创建t的拷贝

时间: 2024-08-24 14:24:30

第12章 动态内存的相关文章

C++ Primer学习总结 第12章 动态内存

第12章 动态内存 1.    申请并使用shared_ptr.  P400 2.    shared_ptr计数. P402 赋值, 拷贝, 向函数传递一个智能指针, 或函数返回一个智能指针都会增加当前智能指针的计数. 3.    不同对象间利用智能指针共享数据的例子. 4.    使用new来动态申请内存. P407 默认情况下,new申请的内存对象都是默认初始化的. 5.    new申请的const对象必须初始化. P408 如果申请内置类型, 那么必须用括号()初始化. 如果申请类类型

《C++primer》v5 第12章 动态内存 读书笔记 习题答案

这一章暂时没写完,先留着以后再写. 在C++程序中,程序员可以给手动开辟内存,但是这块内存需要手动释放,不便管理,因此新标准提供智能指针类型来管理动态对象.它负责自动释放所指向的对象. shared_prt允许多个指针指向同一个对象 unique_ptr独占所指向的对象 weak_ptr是一个弱引用,指向shared_ptr所管理的对象 一些操作: p=q;//递减p的引用计数,递增q的引用计数 shared_ptr<T> p(q);//p是q的拷贝,递增q的引用计数 通过make_share

深入理解java虚拟机-第12章Java内存模型与线程

第12章 Java内存模型与线程 Java内存模型  主内存与工作内存: java内存模型规定了所有的变量都在主内存中,每条线程还有自己的工作内存. 工作内存中保存了该线程使用的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行. 内存间交互操作: 1 lock 作用于主内存的变量,它把一个变量标识为一个线程独占的状态. 2 unlock 作用于主内存的变量,把锁定的变量释放出来 3 read 作用于工作内存的变量,把一个变量的值从主内存传输到线程的工作内存中. 4 load 作用于工作

C++笔记(12):动态内存和智能指针

动态内存和智能指针 动态内存: 1.针对堆里面存放的对象 2.使用new delete运算符 3.智能指针:shared_ptr(多个指针指向同一个对象);  unique_ptr(一个指针指向一个对象);     weak_ptr(弱引用,管理shared_ptr) 4.标准库函数:make_shared<int>()

第十二章 动态内存与智能指针

动态内存与智能指针 [智能指针]头文件#include<memory>shared_ptr: 允许多个指针指向同一个对象unique_ptr: "独占"所指向的对象weak_ptr:伴随类,它是一种弱引用,指向shared_ptr所管理的对象. 原文地址:https://www.cnblogs.com/sunbines/p/8552298.html

12.1 动态内存与智能指针

//练习12.10-11 shared_ptr<int> p(new int(42)); //process(p); //process(shared_ptr<int>(p)); //用p来初始化创建一个临时的智能指针 //也指向p所指向的内存 process(shared_ptr<int>(p.get())); //用p.get()返回的内置指针来初始化创建一个 //临时的智能指针,指向p所指向的内存 //当离开process函数的作用域时,这个临时智能指针会被销毁

12.1动态内存与智能指针

1.shared_ptr<>:允许多个指针指向同一个对象 初始化方式: shared_ptr<int> p1 = make_shared<int>(10);//最好使用这种方式 shared_ptr<int> p2(new int(20)); //只能用直接初始化方式 和普通指针有一样的操作,*,->,swap等 支持拷贝与赋值与自定义删除器,特别地: p.get()能返回p中保存的指针,如果指针指针释放了其对象,返回指针所指的对象也就消失了. p.u

第12章 Java内存模型与线程

1. Java内存模型 Java虚拟机规范中试图定义一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致性的并发效果.在此之前,主流程序语言直接使用物理硬件(或者说是操作系统的内存模型),因此会由于不同平台上内存模型的差异,导致程序在一套平台上并发完全正常,而在另一套平台上并发访问却经常出错. 1. 主内存与工作内存 Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.此处的

【C++ Primer | 12】动态内存与智能指针

#ifndef MY_STRBLOB_H #define MY_STRBLOB_H #include<iostream> #include<vector> #include<memory> #include<initializer_list> using namespace std; class StrBlob { public: typedef vector<string>::size_type size_type; StrBlob(); St