C++内存管理范例

zac*_*zac 12 c++ memory-management stl c++11

我正在从C转向C++ 11并试图找出C++ 11程序(或任何具有内置异常的现代语言)的内存管理范例.具体来说,我在游戏开发方面遇到了麻烦,内存耗尽是一个真正的问题.

在C中,我用来检查malloc的返回值; 并且通常使用自定义分配器.

使用C++,我很困惑; 虽然我喜欢如何构建STL容器,允许自定义分配器.由于STL容器都管理自己的内存,因此只需向向量添加元素即可std::bad_alloc.我该如何防范这些事情?我听说在try/catch块中包装所有抛出的调用都非常昂贵.

但是,允许异常向上移动callstack将允许一堆不能完全执行的函数,并且会导致一些非常棘手的代码.即,如果A->B->C->D是一个callstack,D抛出和A捕获,那么B,C并且D可能由于无法正常完成执行而可能产生一些奇怪的问题.

此外,该nothrow论点似乎允许非常类似C的代码; 虽然我现在看不到普通malloc的好处.

有哪些最佳实践用于编写防异常安全的C++代码以防止内存不足问题?

编辑: 关于progammers.stackexchange的相关答案,主张在控制台中进行无异常的C++设计.不确定这些论点是否仍适用于第8代游戏机

meg*_*dan 8

我的答案将更多地面向游戏开发,因为这是我的背景,这是你感兴趣的一部分.不同类型的应用程序将有不同的要求.

游戏通常预先分配所有动态内存并坚持预算.控制台尤其具有硬内存限制,大多数游戏都希望使用它.

预先分配所有内容有几个原因.

一,表现.内存分配很慢.你想不惜一切代价避免它.如果您事先分配所有内容,则可以编写自定义的高性能内存分配器,如池分配器,堆栈分配器等,只需从预分配的缓冲区中获取内存.为手头的任务选择最佳分配器非常重要.

第二,如果游戏内存不足,你会很快知道.在开发过程中,如果内存不足并且需要调整使用率,您将崩溃,但最终版本不会崩溃,因为您已预先分配并停留在内存预算中.

对于例外情况,许多(但不是全部)游戏会因性能原因再次禁用异常.事实上,一些控制台编译器甚至不支持异常.然后,您将需要使用没有例外的STL库,或者实现您自己的容器.许多游戏团队出于性能原因选择实现自己的游戏,并且更好地将它们与自定义内存分配器集成.

也就是说,动态内存分配,STL和异常对于较小的个人项目/游戏来说可能非常好,但请记住大型,高性能,实时游戏所需的内容.

为了安全,我绝对会使用RAII.这是它的目的.此外,我会建议使用智能指针像std::unique_ptrstd::shared_ptr内存管理.加上RAII,如果你的构造函数抛出,内存将被释放.


Che*_*Alf 6

退出范围时,使用析构函数自动清理.这就是所谓的RAII,资源获取是初始化,虽然这个首字母缩略词不是最好的设计.所有标准容器等都会自动清理.

在基于垃圾收集的C#和Java等语言中,您可以使用try块和"使用"语句来编写代码.Java刚刚得到了(try语法IIRC的一部分); 它从一开始就在C#中(关键字using); 在Python中它被称为with; 和C++没有它,也不需要它.我曾经WITH为C++ 创建了一个宏,一个聪明的小黑客,以为我会一直使用它,但我没有使用过它,只是在创建它之后立即尝试:在C++ RAII中完成所有工作.

总结:使用RAII,即使用析构函数,然后让这些异常传播.


关于内存耗尽,通常只是被视为"我们已经完成了",除了尽可能有序地终止之外无所事事.

但是,在内存耗尽时可能会释放一个可以解除分配的缓冲区,从而为清理工作留出一些工作内存并没有什么坏处.


C++不区分异常(致命,如内存耗尽)和异常(一般不是致命的失败).