博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++Primer :第十二章:直接管理内存 new and delete
阅读量:2432 次
发布时间:2019-05-10

本文共 3724 字,大约阅读时间需要 12 分钟。

使用new动态分配和初始化对象

在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针:

int *pi = new int;  //pi指向一个动态的、未初始化的无名对象

此new表达式在自由空间构造一个int类型的对象,并返回指向该对象的指针

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

string *ps = new string;   //初始化为空stringint *pi = new int;       //pi指向一个未初始化的int

我们可以使用传统的构造方式,用圆括号,或者用列表初始化

int *pi = new int(1024);     //p指向的对象的值是1024vector
*pv = new vector
{
0,1,2,3,4,5,6,7,8,9}; //vector有10个元素,值依次为0到9

也可以对动态分配的对象进行值初始化,只需在类型名后跟一对空括号即可

string *ps1 = new string;   //默认初始化为空stringstring *ps = new string();   //值初始化为空stringint *pi1 = new int;         //默认初始化,*pi1的值是未定义的int *pi2 = new int();       //值初始化为0,*pi2的值为0

对于定义了自己的构造函数的类类型(例如string)来说,要求值初始化是没有意义的;不管采用什么形式,对象都会通过默认构造函数来初始化。

对于内置类型,值初始化的内置类型对象有着良好定义的值,而默认初始化的对象的值则是未定义的。对于类中那些依赖于编译器合成的默认构造函数的内置类型成员,如果它们未在类内被初始化,那么它们的值也是未定义的。

动态分配的const对象

用new分配const对象是合法的:

//分配并初始化一个const intconst int *pci = new const int(1024);//分配并默认初始化一个const的空stringconst string *pcs = new const string;

类似其他任何const对象,一个动态分配的const对象必须进行初始化。对于一个定义了一个默认构造函数的类类型,其const动态对象可以隐式初始化,而其他类型的对象就必须显式初始化。由于分配的对象是const的,new返回的指针也是一个指向const的指针

内存耗尽

如果new不能分配所需要的内存空间,它会抛出一个类型为bad_alloc的异常,我们可以改变使用new的方式来阻止它抛出异常
bad_alloc和nothrow都定义在头文件new中

int *p1 = new int;   //如果分配失败,new抛出std::bad_allocint *p2 = new (nothrow) int;   //如果分配失败,new返回一个空指针

释放动态内存

delete表达式接受一个指针,指向我们想要释放的对象:
传递给delete的指针必须指向动态分配的内存,或者是一个空指针。释放一块并非new分配的内存,或者将相同的指针值释放多次,其值都是未定义的。
虽然一个const对象的值不能被改变,但它本身是可以被销毁的
动态对象的生存期直到被释放时为止

delete之后重置指针值

当delete一个指针后,指针值就变成无效了,但指针仍然保存着动态内存(已经释放)的地址。在delete之后,指针就变成了空悬指针,指向一块曾经保存数据但现在已经无效的内存的指针。
避免空悬指针的方法:在指针即要离开其作用域之前释放掉它所关联的内存。这样,在指针关联的内存被释放掉之后,就没有机会继续使用指针了。如果我们需要保留指针,可以在delete之后将nullptr赋予指针。

这只是提供了有限的保护

动态内存的一个基本问题是可能有多个指针指向相同的内存。在delete内存之后重置指针的方法只对这个指针有效,对其他任何仍指向(已释放)内存的指针是没有用的

int *p = new int(42);auto q = p;   //q和p指向相同的内存delete p;     //q和p均变为无效p = nullptr;  //指出P不再绑定到任何任何对象

但是重置p对于q没有任何作用,在我们释放p所指向的内存时,q也变为无效了。在实际系统中,查找相同内存的所有指针是异常困难的

编写函数,返回一个动态分配的int的vector,将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector元素中。再将vector传递给另一个函数,打印读入的值,记得在恰当的时刻delete vector。

#include 
#include
using namespace std;vector
*new_vector() {
return new (nothrow) vector
;}void read_int(vector
*pv) {
int v; while (cin >> v) {
pv->push_back(v); } cin.clear();}void print_int(vector
*pv) { for (const auto& v : *pv) { cout << v << " "; } cout << endl;}int main() { vector
* pv = new_vector(); if (!pv) { cout << "内存不足" << endl; return -1; } read_int(pv); print_int(pv); delete pv; pv = nullptr; return 0;}

用shared_ptr而不是内置指针重写上面的函数

#include 
#include
#include
using namespace std;shared_ptr
> new_vector() {
return make_shared
>();}void read_int(shared_ptr
> pv) { int v; while (cin >> v) { pv->push_back(v); } cin.clear();}void print_int(shared_ptr
> pv) { for (const auto& v : *pv) { cout << v << " "; } cout << endl;}int main() { shared_ptr
> pv = new_vector(); if (!pv) { cout << "内存不足" << endl; return -1; } read_int(pv); print_int(pv); return 0;}

解释下面代码执行的结果并说明存在的问题

int *q = new int(42), *r = new int(100);r = q;

1、存在内存泄漏的问题,将q地址赋值给r,会导致q和r同时指向42的内存地址,而r中原来保存的地址将再无指针管理

2、容易造成指针空悬的问题。因为r和q指向同一个动态对象,如果程序编写不当,释放了其中一个指针,如果再使用另一个指针,就会造成无法预测的结果,因为该指针所指向的原内存已经被释放了

auto q2 = make_shared
(42), r2 = make_shared
(100);r2 = q2;

用shared_ptr很好的解决了上面产生的两个问题。首先分配了两个共享的对象,分别由共享指针p2和q2指向,因此它们的引用计数均为1。接下来,将q2赋予r2,赋值操作会将q2指向对象的地址赋予r2,并将r2原来指向的对象的引用计数减1,将q2指向的对象的引用计数加1。这样,前者的引用计数为0,其占有的内存空间被释放,不会造成内存泄漏。而后者的引用计数变为2,也不会因为r2和q2之一的销毁而释放它的内存空间,因此也不会造成空悬指针的问题。

转载地址:http://ftxmb.baihongyu.com/

你可能感兴趣的文章
对移动通信网络优化工作的一些见解(转)
查看>>
正确网络配置建议 减少卡机死机的关键(转)
查看>>
智能手机Smartphone开发从零起步(五)(转)
查看>>
防止木马,教你找回被盗的QQ号码(转)
查看>>
SEO技巧中你可能没有注意的细节(转)
查看>>
微软开始二代Windows Live 不见Cloud OS踪影
查看>>
SQL Server 7.0 入门(四)(转)
查看>>
心得分享:防火墙程序使用的几点经验(转)
查看>>
创建ISAPI扩展(转)
查看>>
ORACLE 9I 重建 TEMP 表空间(转)
查看>>
Windows Server 2003 R2 Beta 2将公测(转)
查看>>
Pocket PC应用程序中使用SQL Server CE(转)
查看>>
完美解决不修改NTLDR-最后一次正确配置的问题(修正)(转)
查看>>
在双硬盘上安装独立32位和64位双系统(转)
查看>>
MYSQL列类型参考(转)
查看>>
病毒及木马预警一周播报(06.04.17~04.23)(转)
查看>>
黑客口述:我的第一台3389肉鸡的经历(转)
查看>>
关于 cleanup stack 和 two phase consturction [1](转)
查看>>
Oracle数据导入导出imp/exp (转)
查看>>
如何构建固定网(PSTN)短消息系统(转)
查看>>