当前位置: 代码迷 >> 综合 >> 【c++ primer读书笔记】【第12章】动态内存
  详细解决方案

【c++ primer读书笔记】【第12章】动态内存

热度:4   发布时间:2023-12-21 18:11:11.0

1、在c++中,动态内存管理通过一对运算符完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针。delete,接受一个动态对象的指针,销毁该对象,并释放与之相关的内存。

2c++11新标准库提供了两种智能指针类型管理动态对象,智能指针的行为类似常规指针,区别是它自动释放所指向的内存。shared_ptr允许多个指针指向同一个对象,unique_ptr独占所指向的对象,伴随类weak_ptr指向share_ptr所管理的对象。

3、最安全的使用动态内存的方法是使用一个make_shared的函数。此函数在动态内存中分配一个对象并初始化,返回指向此对象的shared_ptr

shared_ptr<int> p1 = make_shared<int>(42); //p1是指向一个值为41的int的shared_ptr
shared_ptr<string> p2 = make_shared<string>(5, '9');//p2指向一个值为“99999”的string
shared_ptr<int> p3 = make_shared<int>(); //p3指向一个值初始化的int

4、shared_ptr的拷贝和赋值

shared_ptr<int> p = make_shared<int>(42); //p是指向一个值为42的int的shared_ptr
auto q(p);//p和q指向相同对象,此对象有两个引用者
auto r = make_shared<int>(42);
r = q; //给r赋值,令它指向另一个地址,递增q指向的对象的引用计数,递减r原来指向的对象的引用计数//r原来指向的对象已没有引用者,会自动释放
我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数,无论我们拷贝一个share_ptr,计数器都会递增。当我们给一个shared_ptr赋值或者shared被销毁,计数器就会递减。

#include<iostream>
#include<memory>
using namespace std;int main(){shared_ptr<int> p = make_shared<int>(42); //p是指向一个值为41的int的shared_ptrcout << "p use_count:" << p.use_count() << endl; //返回与p共享对象的智能指针数量cout << "p unique:" << p.unique() << endl; //若p.use_count()为1,返回true,否则返回falseauto q(p);//p和q指向相同对象,此对象有两个引用者cout << "q use_count:" << q.use_count() << endl;//返回与q共享对象的智能指针数量cout << "q unique:" << q.unique() << endl;//若q.use_count()为1,返回true,否则返回falseauto r = make_shared<int>(42);cout << "r use_count:" << r.use_count() << endl;r = q; //给r赋值,令它指向另一个地址,递增q指向的对象的引用计数,递减r原来指向的对象的引用计数//r原来指向的对象已没有引用者,会自动释放cout << "r use_count:" << r.use_count() << endl; //与r共享对象的智能指针数量为3,分别是p,q,rcout << "q use_count:" << q.use_count() << endl;//与q共享对象的智能指针数量为3,分别是p,q,rsystem("pause");return 0;
}

5、当指向对象的最后一个shared_ptr被销毁时,shared_ptr 类会自动销毁此对象。它通过析构函数完成销毁工作。shared_ptr 的析构函数会递减它所指向的对象的引用计数,如果引用计数变为0,shared_ptr的函数就会销毁对象,并释放它占用的资源。

6、一个unique_ptr 拥有它所指向的对象,和shared_ptr不同,某个时刻只能有一个unique_ptr 指向一个给定对象,当unique_ptr 被销毁时,对象也被销毁。

#include<iostream>
#include<memory>
#include<string>
using namespace std;int main(){unique_ptr<string> p1(new string("aaa"));//unique_ptr<string> p2(p1);  //错误,unique_ptr不支持拷贝unique_ptr<string> p3;//p3 = p1;     //错误,unique_ptr不支持赋值unique_ptr<string> p4(p1.release()); //p1.release()将p1置为空,将所有权从p1转移给p4unique_ptr<string> p5(new string("bbb"));p5.reset(p4.release()); //reset释放了p5原来指向的内存,p5指向了p4原来指向的内存cout << *p5 << endl;system("pause");return 0;
}

7类似shared_ptr,unique_ptr默认情况下用delete释放它指向的对象。和shared_ptr一样,我们可以重载一个unique_ptr中默认的删除器类型。重载一个unique_ptr中的删除器会影响到unique_ptr类型及如何构造该类型的对象。

格式:

//p指向一个类型为objT的对象,并使用一个类型为delT的对象释放objT对象
//它调用一个名为fcn的delT类型对象
unique_ptr<objT, delT> p(new objT, fcn);

8、weak_ptr 是一种不控制对象生存期的智能指针,它指向由一个shared_ptr 管理的对象。将weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数,当最后一个指向对象的shared_ptr被销毁,即使有weak_ptr指向该对象,对象还是会被释放。

9、allocator类

allocator类将内存分配和对象构造分离开来,它分配的内存是原始的,未构造的。

#include<iostream>
#include<memory>
#include<string>
using namespace std;int main(){allocator<string> alloc; //定义了一个名为alloc的allocator对象,它为类型为string的对象分配内存auto const p=alloc.allocate(10); //分配内存保存10个类型为string的对象auto q = p; //q指向最后构造的元素之后的位置alloc.construct(q++, 5, 'c');//*q为ccccc,q指向的内存中构造一个对象alloc.construct(q++);  //*q为空字符串alloc.construct(q++, "hi"); //*q为hicout << *p << endl; //正确,输出ccccc//cout << *q << endl; //错误,q指向未构造的内存while (q != p)alloc.destroy(--q); //销毁真正构造的stringalloc.deallocate(p, 10);//释放p中地址的内存,这快内存保存了n个string对象,p必须是allocte返回的指针,n必须是allocate(n)的n  //在调用deallocate时必须先毁坏这块内存中创建的对象  system("pause");return 0;
}

10、allocator类的拷贝和填充未初始化内存的算法

#define _SCL_SECURE_NO_WARNINGS  //为了防止VS2013报错
#include<iostream>
#include<memory>
#include<vector>
using namespace std;int main(){vector<int> vec{ 1,2,3 };vector<int> vec2{ 5,6,7,8};allocator<int> alloc; auto p1=alloc.allocate(vec.size()*4); auto p2 = uninitialized_copy(vec.begin(), vec.end(), p1); //uninitialized_copy(b,e,b2); //从迭代器b和e指定的输出范围中拷贝元素到迭代器b2指定的未构造的原始内存中,b2指向内存必须足够大auto p3=uninitialized_copy_n(vec2.begin(), vec2.size(), p2);//uninitialized_copy_n(b, n, b2) 从迭代器b指向的元素开始拷贝n个元素到到以b2开始的内存中auto p4 = uninitialized_fill_n(p3, vec.size(), 10);//uninitialized_fill_n(b, n, t) 从b指向的内存地址创建n个对象,t是填充的元素uninitialized_fill(p4, p4 + 2, 9);//uninitialized_fill(b, e, t)      在b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝for (size_t i = 0; i < vec.size() * 4; ++i)cout << *p1++ << " ";cout << endl;system("pause");return 0;
}