静态(全局)内存:存储局部static对象、类static数据成员、定义在任何函数之外的对象。static对象在使用之前分配内存,程序结束时销毁。 内存在程序编译的时候已经分配好,运行期间都存在。 栈内存:存储定义在函数内的非static对象(局部非静态变量)。仅在定义的函数块运行时才存在。 栈内存分配运算内置于指令集,效率高,但是容量有限。 堆内存(自由空间):程序运行时分配的对象,声明周期由程序来控制。 动态内存分配。 常量区:存放常量字符串,程序结束时由系统释放。 代码区:存放函数体(类成员函数和全局区)的2进制代码。 静态全局变量、全局变量区别 静态局部变量、局部变量区别 直接使用new/delete的类不能使用类对象的拷贝、赋值和销毁的默认形式。 默认情况下,动态分配的对象是默认初始化的,也就是内置类型的值是未定义的,类类型的对象将使用默认构造函数构造。 可以使用auto来推导类型 定位new 关于数组 delete之后指针变成了悬空指针,在delete之后置为nullptr。 shared_ptr:允许多个指针同时指向同一个对象。 可以使用make_shared标准库函数来创建一个shared_ptr。 shared_ptr只有在引用计数为0时才会销毁其所指向的对象。 shared_ptr和new的结合使用 不要混合使用智能指针和内置指针 不要使用get来初始化智能指针或者为智能指针赋值 reset()操作 使用智能指针,即使程序出现异常提前结束,智能指针也能保证正确地释放指针指向的内存。而内置指针无法实现这一点。 注意陷阱 某个时刻只能有一个unique_ptr指向一个给定对象,不支持普通的拷贝和赋值操作。 release()返回unique_ptr当前保存的指针并将其置为空,常用来初始化或给另一智能指针赋值。 唯一一个可以拷贝unique_ptr的例子就是从函数返回一个unique_ptr。 auto_ptr是一个早期版本的智能指针,具备部分unique_ptr功能,但已被废弃,尽量不要使用。 weak_ptr是一种不控制所指向对象生命周期的智能指针,指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr上不会改变shared_ptr的引用计数。 关于动态数组,使用new T[]分配返回的并不是一个数组,而是一个指向数组元素类型的指针。动态数组并不是数组类型。 标准库提供了一个可以管理new分配的动态数组的unique_ptr。 shared_ptr默认不支持管理动态数组,如果想使用shared_ptr来管理动态数组,必须提供自己的删除器。 使用allocator类将内存的分配和对象的构造分离开来。 allocator分配的内存是原始的,未构造的。 如果觉得向上面一个一个construct比较麻烦,可以使用标准库的拷贝填充算法。文章目录
动态内存
C++内存分配模型
静态全局变量、全局变量、静态局部变量、局部变量的区别
直接管理内存
new分配的内存是无名的。int *p = new int;
也可以通过在类型名后面加上空括号来使用值初始化。int *p = new int(); //值初始化,*p=0
string obj("hi"); auto p = new auto(obj); //此时p为string* auto p = new auto{a, b, c}; //错误,只能由单个初始化器
int *p = new int; //如果分配失败,抛出std::bad_alloc异常 int *p2 = new (nothrow) int; //定位new,如果分配失败,返回空指针,bad_alloc和nothrow定义在头文件new中
int* p = new int[10](); //10个值初始化的int delete [] p;
malloc/new、free/delete的区别
智能指针
unique_ptr:只允许一个指针指向某一对象。
weak_ptr:弱引用,指向shared_ptr所管理的对象。
都定义在memory头文件中。shared_ptr
shared_ptr特有操作
make_shared (args)
返回一个shared_ptr,指向一个动态分配的类型为T的对象,使用args初始化此对象。
shared_ptrp (q)
p是shared_ptr q的拷贝:此操作会递增q中的计数器,q中的指针必须能转换成T*
p = q
shared_ptr所保存的指针必须能互相转换,此操作会递减p的引用计数,递增q的引用计数,若p的引用计数变为了0,则释放其管理的原来的内存。
p.use_count()
返回与p共享对象的智能指针个数,可能会很慢。
p.unique()
若p.use_count()为1返回true,否则返回false
shared_ptr<int> p1 = make_shared<int> (42); //创建一个指向442的shared_ptr shared_ptr<string> p2 = make_shared<string>(10, 'o'); auto p3 = make_shared<vector<string>>(); auto p4(p3); //p3p4指向相同对象
shared_ptr<string>sp = make_shared<string>(10, 'c'); //sp指向一个值为cccccccccc的string //sp2指向一个值初始化的int,即值为0 shared_ptr<int>sp2 = make_shared<int>();
//factory返回一个shared_ptr,指向一个动态分配的对象 shared_ptr<string> factory(){ //一些操作 return make_shared<string>("hi"); } void use_factory(T arg){ shared_ptr<string> p = factory(); //使用p }//p离开函数作用域,引用计数变为0,所指向的内存的被释放 shared_ptr<string> use_factory(){ shared_ptr<string> p = make_shared<string>("hi"); // return p; //返回p时,会递增引用计数 } //p离开了作用域,但是所指向的内存没有被释放。
接受指针参数的智能指针的构造函数是explicit的,也就是说不能将一个内置指针隐式转换成一个智能指针。shared_ptr<int> p1 = new int(1024); //错误,不能使用赋值初始化 shared_ptr<int> p2(new int(1024)); //正确,直接初始化
void process(shared_ptr<int> ptr){ //参数是传值方式,也就是调用时实参会被拷贝,引用计数会增加 //使用ptr } //ptr离开作用域,引用计数减一 //正确使用方法,传递一个shared_ptr shared_ptr<int> p(new int(10)); process(p); //正确,拷贝p会增加它的引用计数,在process内的引用计数至少为2 int i = *p; //正确, 引用计数至少为1 //错误用法 int*x(new int(1024)); process(x); //错误,不能将一个int*转换成shared_ptr<int> process(shared_ptr<int>(x)); //可以传递,但是函数执行完后x所指向的内存会被释放 int j = *x; //错误,此时x指向的内存已被释放。
get()返回一个指向智能指针管理对象的内置指针。
使用get返回指针的代码不能delete此指针。shared_ptr<int> sp (new int(10)); int *p = sp.get(); //正确 { //两个独立的shared_ptr指向相同的内存,这两个shared_ptr的引用计数都是1,该程序块内的shared_ptr失效后会销毁其所指向的对象。 shared_ptr<int> q(p); } int foo = *sp; //错误,此时sp所指向的内存已被释放
shared_ptr<int> sp = make_shared<int>(10); sp.reset(); //此时sp的引用计数为0,会释放其所指向的对象 sp.reset(new int(1024)); //sp指向一个新的值为1024的int对象
unique_ptr
初始化unique_ptr必须使用直接初始化形式。unique_ptr<int> up (new int(10)); unique_ptr<int> up2 (up); //错误。不支持拷贝 unique_ptr<int> up3 = up; //错误,不支持赋值
unique_ptr操作
unique_ptr<T, D> u1;
空的unique_ptr,会使用类型为D的可调用对象来释放它所指向空间。D默认为delete操作符
unique_ptr<T, D> u1 (d);
空unique_ptr,调用类型为D的对象d来代替delete
u = nullptr;
释放u指向的对象,将u置空
u.release();
u放弃对指针的控制权,返回所指向的指针,并置空u
u.reset();
释放u所指向的对象
u.reset(q);
令u指向内置指针q,否则置空u
unique_ptr<string> p1 (new string("hi")); unique_ptr<string> p2 (new string("jack")); //将p1的所有权转移给p2 p2.reset(p1.release());
unique_ptr<int> clone(p){ return unique_ptr<int>(new int(p)); } //这样也行 unique_ptr<int> clone(p){ unique_ptr<int> ret (new int(p)); return ret; }
weak_ptr
不能直接使用weak_ptr访问所指向的对象,而需要使用lock()成员函数。auto p = make_shared<int>(42); weak_ptr<int> wkp (p); //直接初始化wkp auto mp = wkp.lock(); //mp指向wkp所指向的对象。
动态数组
auto dp = new int[10]; //10个int的数组,返回指向首元素的指针 auto ds = new string[10]; //同理 auto de = new int[0]; //动态分配一个空的数组是合法的,但是不能解引用 delete [] dp; delete [] ds; //释放动态数组空间,数组元素按逆序销毁。 delete [] de;
unique_ptr<int[]> up (new int[10]); up.release(); //自动调用delete[]销毁指针
指向数组的unique_ptr的操作
指向数组的unique_ptr不支持成员访问运算符(.和->)
unique_ptr<T[]> u;
u可以指向一个动态分配的数组
unique_ptr<T[]> u(q);
u指向内置指针所指向的动态数组
u[i]
返回u拥有的数组中的第i个元素。
shared_ptr<int> sp (new int[10], [](int *p) {delete [] p;}); sp.reset(); //调用lambda表达式delete[]数组
allocator类
可以在分配的内存上按需构造对象,提高效率。
如果不使用allocator,没有默认构造函数的类就无法使用动态分配数组了。
allocator类及其算法
allocator a;
定义allocator对象a,可以为类型T的对象分配内存
a.allocator(n);
分配一个保存n个类型为T的对象的未构造内存
a.construct(p, args);
p必须是指向类型为T*的未构造的内存,args被传递给类型为T的构造函数,用于在内存中构造对象。
a.destroy§;
对p指向的对象执行析构函数。
a.deallocate(p, n);
释放从T* p所指向的位置开始的n个类型为T的对象,p必须是由allocator返回的指针,n必须是创建时的大小。在deallocate之前,内存中的对象必须先被destroy。
allocator<string> alloc; auto p = alloc.allocate(10); //分配10个未初始化的string auto q = p; //q指向最后构造的元素之后的位置 alloc.construct(q++); //q为空字符串 alloc.construct(q++, 10, 'c'); //*q为cccccccccc cout << *p << endl; //正确,因为p所指向的内存已有对象 cout << *q << endl; // 错误,q指向未构造的内存,因为q++指向下一个未构造的内存了。 while(q != p){ alloc.destory(--q); //销毁q指向的对象 } //之后可以将分配的内存释放掉 alloc.deallocate(p, 10); //之所以是10是因为deallocate的大小必须和allocate的大小一致
拷贝和填充未初始化内存的算法
allocator拷贝填充算法
uninitialized_copy(b, e, b2);
从迭代器b和e指出的输入范围中拷贝元素到迭代器b2指定的未构造的原始内存中,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
//p指向一个分配大小为vi两倍的内存 auto p = alloc.allocate(vi.size() * 2); //将vi中的元素拷贝到p指向的内存中, 返回的q指向最后一个构造的对象的后一个位置 auto q = uninitialized_copy(vi.begin(), vi.end(), p); uninitialized_fill_n(q, vi,size(), 42); //将剩余的内存全部初始化为42
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算