0

来自 Java 和 C#,我习惯于执行以下操作:

byte[] myArray = new byte[10];

并且不在乎必须清理它。但是,现在我使用的是 C++,显然您必须小心分配和内存泄漏。

我听说有些人说你应该不惜一切代价避免动态分配,但我也看到有些人“自由地”使用它,new当本地堆栈变量就足够了时,使用运算符来实例化类:

DatabaseConnection conn = new DatabaseConnection("127.0.0.1");
// or
DatabaseConnection conn("127.0.0.1");

我知道在堆上分配的数组要慢得多,但我更喜欢更具可读性和可扩展性的代码,而不是由于使用动态内存而可能发生的小幅性能损失。

所以,我的问题是:你真的应该不惜一切代价避免堆分配吗?

4

5 回答 5

5

我建议在这种情况下,使用它很好:

byte myArray[10]; 

如果您需要一个可以复制的数组(例如从函数返回),那么使用vector<byte>是正确的解决方案。

最后的手段应该是使用new,并且仅在数据需要保存在函数之外时才分配小区域。

不幸的是,书籍并不总是告诉你好的做法,或者展示你应该和不应该使用的很好的例子,例如new- 相反,它们显示的东西int *arr = new int[5];可能比实际数据占用更多的开销空间。

当然,一切都new必须是deleted。通过执行自动清理,使用智能指针(shared_ptrunique_ptr)将有很大帮助。

于 2013-08-08T17:42:26.360 回答
3

只要有可能?是的。不惜一切成本?不会。动态分配通常是解决问题的最简单方法。

但是,避免new不惜一切代价使用。依靠make_sharedmake_unique生产单个对象,而容器则喜欢std::vector用于多个对象。您没有任何借口可以使用delete.

于 2013-08-08T17:45:44.663 回答
1

是的,这是真的,您应该尽可能避免堆分配。在您提到的情况下,您应该使用标准库提供的容器,如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_arrayshared_ptr/ shared_arrayweak_ptrintrusive_ptr; Poco 为您提供AutoPtr等。C++03 中甚至还有一个智能指针auto_ptr,但我强烈反对使用它;现在不推荐使用它,并且它具有非常奇怪的复制行为,因为 C++03 不支持右值引用/移动语义。

于 2013-08-08T17:41:57.343 回答
1

你总是可以从两个向量来处理这样的问题;可维护性/可读性和性能。有时第二个很重要,有时不重要。有时你不在乎第一个。但是,在这种情况下,我会说将尽可能多的东西放在自动内存(“堆栈”)与动态内存(“堆”)上(大多数情况下)在这两个方面都获胜。

与更改堆栈指针相比,分配动态内存是如此缓慢,几乎没有关于性能的争论。但是,如果您分配的东西不会在动态内存中离开其范围,则必须注意在范围之后释放内存,如果您忘记了,您不仅会泄漏内存,而且可能会破坏正确性,因为析构函数不是称为。在这方面它的可维护性较差。

对每一个单曲都持怀疑态度new并认为它很臭是有帮助的。它可以防止您不必要地过度使用它。

于 2013-08-08T17:43:06.820 回答
0

动态分配的一些问题:

  1. 内存泄漏(如果您忘记删除对象)
  2. 大量分配/释放请求 - 另一方面,堆栈分配只是在调用函数时移动堆栈指针一次。一些自动变量甚至可以驻留在寄存器中而不占用内存。
  3. 堆碎片。

基本上,只有在用尽所有其他选项时才使用堆。

于 2013-08-08T17:43:37.207 回答