为什么C++程序员要尽量减少使用new?

为什么C++程序员要尽量减少使用new?

有两种广泛使用的内存分配技术:自动分配和动态分配。通常,他们分别对应内存区域:栈和堆。

栈始终以顺序方式分配内存。 它可以这样做,因为它要求你以相反的顺序释放内存(先进先出,FILO)。许多编程语言都采用这样的局部变量的存储分配技术。 它非常非常快,因为它需要很少的bookkeeping,并且分配的下一个地址是隐式的。
在C++中,这称为自动存储,因为存储被自动声明。 一旦当前代码块(使用{}分隔)执行完毕之后,该块中所有变量的内存将自动回收。这也是调用析构函数来清理资源的时刻。

堆允许更灵活的内存分配模式。bookkeeping更复杂,分配更慢。因为没有隐式释放点,所以必须手动释放内存,使用delete或delete []。然而,缺少隐式释放点是堆灵活性的关键。
使用动态分配的原因
即使使用堆较慢,并且可能导致内存泄漏或内存碎片,动态分配也有非常好的用例,因为它的限制较少。
使用动态分配的两个主要原因:
·你不知道在编译时需要多少内存。 例如,当将文本文件读入字符串时,我们通常不知道文件的大小,因此在运行程序之前无法确定要分配多少内存。
·你想要分配内存,就算离开当前代码块后依然保持该内存不释放。 例如,你可能想编写一个返回文件内容的函数string readfile(string path)。 在这种情况下,即使栈可以存储整个文件内容,你也不能把它作为函数的返回值,因为离开这个代码段之后,该内存会被释放。
为什么动态分配通常是不必要的
在C++中有一个干净利落的函数,称为析构函数。这种机制允许你通过将资源的生命周期与变量的生存期对齐来管理资源。 这种技术称为RAII,是C++特别的点。 它将资源封装到对象中。std::string是一个完美的例子。 此代码段:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

实际上分配了可变的内存。std::string对象使用堆分配内存并在其析构函数中释放它。在这种情况下,您不需要手动管理任何资源,仍然可以获得动态内存分配的好处。
而这个片段:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

就是不必要的动态内存分配。 该程序增加了代码量,并增加了忘记释放已分配内存的风险,没有明显的好处。
为什么你应该尽可能多地使用自动存储?
总结起来,尽可能多地使用自动存储功能使你的程序:
·更快的类型;
·运行时更快;
·不易出现内存/资源泄漏。
额外补充
在提到的问题中,还有其他的问题,特别是下面这个类

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

实际上使用起来比下面这个更危险:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

原因是std::string定义了一个拷贝函数。 考虑下面的程序:

int main ()
{
    Line l1;
    Line l2 = l1;
}

使用原始版本,这个程序可能会崩溃,因为它使用相同的字符串,却删除了两次。使用修改版本,每个Line实例将拥有自己的字符串实例,每个实例都有自己的内存,并且都将在程序结束时释放。
其他说明
由于上述所有原因,广泛使用RAII是C++的最佳实践。另外,还有一个并不显而易见的好处。
如果你使用Line类作为一个构造块:

class Table
 {
      Line borders[4];
 };

然后

int main ()
 {
     Table table;
 }

分配的四个std :: string实例,四个Line实例,一个Table实例和所有字符串的内容,一切都自动释放。

你可能感兴趣的:(C++编程,c++,编程语言)