博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c语言ctrl c线程中动态申请的内存,【C++】 外传篇 3_动态内存申请的结果
阅读量:6829 次
发布时间:2019-06-26

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

动态内存的结果

问题: 动态内存申请一定成功吗?

常见的动态内存分配代码

C 代码:

void code()

{

int* p = (int*)malloc(10 * sizeof(int));

if( p != NULL )

{

// ...

}

free(p);

}

C++ 代码:

void code()

{

int* p = new int[10];

if( p != NULL )

{

// ...

}

delete p;

}

必须知道的事实

malloc 函数申请失败时返回 NULL 值

new 关键字申请失败时(根据编译器不同)

返回 NULL 值 (古代)

抛出 std::bad_alloc 异常 (现代)

问题: new 语句中的异常是怎么抛出来的呢?

new 关键字在 C++ 规范中的标准行为

在堆空间申请足够的内存

成功:

在获取的空间中调用构造函数创建对象

返回对象的地址

失败

抛出 std::bad_alloc 异常

new 关键字在 C++ 规范中的标准行为

new 在分配内存时

如果空间不足,会调用全局的 new_handler() 函数

new_handler() 函数中抛出 std::bad_alloc 异常

可以自定义 new_handler() 函数

处理默认的 new 内存分配失败的情况

new_handler() 中,可以手动做一些内存整理的工作,使得更多的堆空间可以被使用。

new_handler() 函数的替换

自定义一个无返回值无参数的函数

调用 set_new_handler() 设置自定义的函数

参数类型为 void(*)()

返回值为默认的 new_handler() 函数入口地址

new_handler() 的定义和使用

void my_new_handler()

{

cout << "No enough memory" << endl;

}

int main(int argc, char* argv[])

{

set_new_handler(my_new_handler);

// ...

return 0;

}

编程实验: new_handler 初探

公用实验代码:

#include

#include

#include

#include

using namespace std;

class Test

{

private:

int m_value;

public:

Test()

{

cout << "Test()" << endl;

m_value = 0;

}

~Test()

{

cout << "~Test()" << endl;

}

void* operator new (unsigned int size)

{

cout << "operator new: " << size << endl;

// return malloc(size);

return NULL; // 注意这里! 模拟内存申请失败

}

void operator delete(void* p)

{

cout << "operator delete: " << p << endl;

free(p);

}

void* operator new[] (unsigned int size)

{

cout << "operator new[]: " << size << endl;

// return malloc(size);

return NULL; // 注意这里! 模拟内存申请失败

}

void operator delete[](void* p)

{

cout << "operator delete[]: " << p << endl;

free(p);

}

};

实验 1:不同编译器中 new_handler() 行为

void my_new_handler()

{

cout << "void my_new_handler()" << endl;

}

void ex_func_1()

{

new_handler func = set_new_handler(my_new_handler); // 注意这里!

try

{

cout << "func = " << func << endl;

if( func )

{

func();

}

}

catch(const bad_alloc&)

{

cout << "catch(catch bad_alloc&)" << endl;

}

}

int main()

{

ex_func_1();

return 0;

}

输出:[g++]

func = 0

输出:[vc++2010]

func = 00000000

输出:[bcc]

func = 0x00401474

catch(catch bad_alloc&)

结论:

默认情况下,g++,vc++2010 并没有提供全局的 new_handler() 函数;

gcc 提供了全局的 new_handler() 函数,并抛出了 bad_alloc 异常。

实验 2:不同编译器 new 失败行为

void ex_func_2()

{

Test* pt = new Test();

cout << "pt = " << pt << endl;

delete pt;

pt = new Test[5];

cout << "pt = " << pt << endl;

delete[] pt;

}

int main()

{

ex_func_2();

return 0;

}

输出:[g++]

Test()

段错误

输出:[vc++2010]

operator new: 4

pt = 00000000

operator new[]: 24

pt = 00000000

输出:[bcc]

operator new: 4

pt = 00000000

operator new[]: 24

pt = 00000000

分析:

g++ 编译生成的可执行文件运行时发生段错误:

new 重载函数返回 NULL, 于是就在 0 地址处创建对象,调用构造函数。构造函数中,m_value = 0,导致段错误。

vc++2010:

如果 new 的重载返回 NULL,对象未创建,构造函数不会被调用

bcc:

如果 new 的重载返回 NULL,对象未创建,构造函数不会被调用

问题:如何跨编译器统一 new 的行为, 提高代码的移植性呢?

解决方案【动态内存分配失败时,返回空指针】

全局范围(不推荐)

重新定义 new / delete 的实现,不抛出任何异常

自定义 new_handler() 函数,不抛出任何异常

类层次范围

重载 new / delete, 不抛出任何异常

单此动态内存分配

使用 nothrow 参数,指明 new 不抛出异常

编程实验:动态内存申请

实验 1: 类层次范围

#include

#include

#include

#include

using namespace std;

class Test

{

private:

int m_value;

public:

Test()

{

cout << "Test()" << endl;

m_value = 0;

}

~Test()

{

cout << "~Test()" << endl;

}

void* operator new (unsigned int size) throw() // 注意这里!

{

cout << "operator new: " << size << endl;

// return malloc(size);

return NULL; // 注意这里! 模拟内存申请失败

}

void operator delete(void* p)

{

cout << "operator delete: " << p << endl;

free(p);

}

void* operator new[] (unsigned int size) throw() // 注意这里!

{

cout << "operator new[]: " << size << endl;

// return malloc(size);

return NULL; // 注意这里! 模拟内存申请失败

}

void operator delete[](void* p)

{

cout << "operator delete[]: " << p << endl;

free(p);

}

};

void ex_func_2()

{

Test* pt = new Test();

cout << "pt = " << pt << endl;

delete pt;

pt = new Test[5];

cout << "pt = " << pt << endl;

delete[] pt;

}

int main()

{

ex_func_2();

return 0;

}

输出:[g++]

operator new: 4

pt = 0

operator new[]: 24

pt = 0

输出:[vc++2010]

operator new: 4

pt = 00000000

operator new[]: 24

pt = 00000000

输出:[bcc]

operator new: 4

pt = 00000000

operator new[]: 24

pt = 00000000

实验 2:单次动态内存分配范围

#include

#include

#include

#include

using namespace std;

void ex_func_3()

{

int* p = new(nothrow) int[10]; // 注意这里!

cout << "p = " << p << endl;

delete p;

}

int main()

{

ex_func_3();

return 0;

}

输出:

p = 0x8300008

实验结论

不是所有的编译器都遵循 C++ 的标准规范

编译器可能重定义 new 的实现,并在实现中抛出 bad_alloc 异常

编译器的默认实现中,可能没有设置全局的 new_handler() 函数

对于移植性要求较高的代码,需要考虑 new 的具体细节

小结

不同的编译器在动态内存分配上的实现细节不同

malloc 函数在内存申请失败时返回 NULL 值

new 关键字在内存申请失败时

可能返回 NULL 值

可能抛出 bad_alloc 异常

关于 new 的小知识点补充:

在指定的内存空间上创建对象(需要手动调用析构函数)

#include

using namespace std;

int main()

{

int bb[2] = {0};

struct ST

{

int x;

int y;

};

ST* pt = new(bb) ST(); // 注意这里!

pt->x = 1;

pt->y = 2;

cout << bb[0] << endl;

cout << bb[1] << endl;

pt->~ST(); // 手动调用析构函数

return 0;

}

输出:

1

2

以上内容参考狄泰软件学院系列课程,请大家保护原创!

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

你可能感兴趣的文章
对比JavaScript中的Continue和Break
查看>>
javascript基础之模块
查看>>
面试题20180302
查看>>
AlloyFinger web 手势学习
查看>>
[Javascript] 实现setInterval函数
查看>>
一篇文章带你学习js数据类型
查看>>
你所要知道的所有关于Angular的变化检测机制
查看>>
GIT入门
查看>>
从零构建一个基于Docker的Laravel应用
查看>>
【332天】每日项目总结系列070(2018.01.03)
查看>>
java源码
查看>>
Container With Most Water -- leetcode
查看>>
Canvas保存图片到七牛云
查看>>
Vue数组的动态响应
查看>>
Node.js源码解析-HTTP请求响应过程
查看>>
preventDefault()、stopPropagation()、return false 之间的区别
查看>>
缓存的Cache Aside模式
查看>>
Node.js中流的使用
查看>>
ES6 常用新特性讲解
查看>>
关于直播几个视频格式的概念总结
查看>>