动态分配的使用
Usage of Dynamic Allocation
来自Java和C#,我习惯于做以下事情:
byte[] myArray = new byte[10];
而不在乎必须把它清理干净。然而,现在我使用的是C++,您显然必须小心分配和内存泄漏。
我听过一些人说,你应该不惜一切代价避免动态分配,但我也看到一些人"自由地"使用它,当本地堆栈变量足够时,使用new
运算符实例化类:
DatabaseConnection conn = new DatabaseConnection("127.0.0.1");
// or
DatabaseConnection conn("127.0.0.1");
我知道在堆上分配的数组要慢得多,但我更喜欢可读性和可扩展性更强的代码,而不是使用动态内存可能会带来的小性能损失。
所以,我的问题是:你真的应该不惜一切代价避免堆分配吗?
我建议在这种情况下,使用
byte myArray[10];
如果您需要一个可以复制的数组(例如从函数返回),那么使用vector<byte>
是正确的解决方案。
最后的手段应该是使用new
,并且如果数据需要在函数外预存,则只分配较小的区域。
不幸的是,书籍并不总是告诉你良好的实践,或者展示了你应该和不应该使用的好例子,例如new
——相反,它们展示了像int *arr = new int[5];
这样的东西——这可能比实际数据占用更多的开销空间。
当然,所有的new
都必须是deleted
。使用智能指针(shared_ptr
或unique_ptr
)将通过执行自动清理来提供很大帮助。
是否有可能?对不惜一切代价?不可以。动态分配通常是解决问题的最简单方法。
但是,确实要不惜一切代价避免使用new
。依靠make_shared
和make_unique
来生成单个对象,而像std::vector
这样的容器可以生成多个对象。没有任何理由让你使用delete
。
您总是可以从两个向量来处理此类问题;可维护性/可读性和性能。有时第二个很重要,有时不重要。有时你不在乎第一个。然而,在这种情况下,我想说,将尽可能多的东西放在自动内存("堆栈")和动态内存("堆")上(大多数时候)在这两方面都是有利的。
与更改堆栈指针相比,分配动态内存的速度太慢了,几乎没有关于性能的争论。但是,如果你在动态内存中分配了不离开其作用域的东西,你必须小心在作用域之后释放内存,如果你忘记了,你不仅会泄漏内存,而且很可能会破坏正确性,因为析构函数没有被调用。在这方面,它的可维护性较差。
对每一个new
都持怀疑态度,并认为它很臭,这会有所帮助。它可以防止你不必要地过度使用。
是的,您应该尽可能避免堆分配。在您提到的情况下,您应该使用标准库提供的容器,如std::vector<byte>
,如注释中所建议的那样。
如果您绝对必须在堆上存储一些东西,请使用RAII(资源获取即初始化),这意味着(堆栈上的)对象在构造时执行获取,在销毁时释放资源。由于C++11有std::unique_ptr
,或者更复杂的std::shared_ptr
(与std::weak_ptr
一起),如果您需要一个资源的多个所有者:
std::unique_ptr<int> unique(new int(42));
auto sp = std::make_shared<int>(42);
如果你还不能使用C++11,几乎每个库都会为你提供某种智能指针——boost会给你scoped_ptr
/scoped_array
、shared_ptr
/shared_array
、weak_ptr
和intrusive_ptr
;Poco给你AutoPtr
等。C++03中甚至有一个智能指针,auto_ptr
,但我强烈反对使用它;现在不赞成使用它,而且它有非常奇怪的复制行为,因为C++03不支持右值引用/移动语义。
动态分配的一些问题:
- 内存泄漏(如果您忘记删除对象)
- 大量的分配/释放请求——另一方面,堆栈分配只是在调用函数时移动堆栈指针一次。一些自动变量甚至可以驻留在寄存器中而不占用内存
- 堆碎片
基本上,只有在用尽所有其他选项的情况下才使用堆。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 在c++中使用动态分配的问题
- 使用递归模板动态分配的多维数组
- 对具有动态分配的内存和析构函数的类对象的引用
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 访问动态分配列表中的元素
- 为什么 std::equal_to会导致动态分配?
- 调用析构函数以释放动态分配的内存
- 动态分配Q_Property变量
- 在 C++ 中搜索动态分配的数组中的出现次数
- 动态分配的聊天数组打印缺失的数据和空
- 在对象指针上调用 Delete 是否会递归删除其动态分配的成员
- 使用动态分配将 char* 复制到另一个字符**
- 使用指针在存在特征库的情况下动态分配 c++ 中的矩阵
- 二维阵列的动态分配
- 0xC0000005:访问冲突写入位置0xCDCDCDCD动态分配错误
- 在运行时为动态分配的内存输入值
- 释放动态分配的内存时是否需要执行此额外步骤
- 动态分配字符数组的内存