C++ vs Java:无限循环创建对象只会导致C++崩溃

cal*_*kon 17 c++ java pointers memory-management

这是我的一本书中的一个问题(没有附上答案),我已经考虑了几天了.答案很简单,C++代码最终会崩溃,因为它在每次迭代后都会创建一个垃圾内存单元?

考虑以下Java和C++代码片段,这是基于GUI的应用程序的两个版本的一部分,它收集用户首选项并使用它们来组装命令及其参数.方法/函数getUserCommandSpecification()返回表示命令代码及其参数的字符串.返回的字符串用于构建所需的命令,然后执行该命令.

假设如下:

(i)在Command对象的while循环中创建(在Java情况下由cmd引用或在C++情况下由cmd指向),不再引用或使用对生成的对象的引用/指针cmd.

(ii)应用程序还定义了一个类Command及其方法/函数execute().

一个.下面详述的两个代码版本中的哪一个最终会崩溃.
湾 解释为什么程序版本崩溃而另一个版本没有崩溃.

Java代码

...
while (true) {
   String commandSpecification = getUserCommandSpecification();
   Command cmd = new Command(commandSpecification);
   cmd.execute();
}
...
Run Code Online (Sandbox Code Playgroud)

C++代码

...
while (true) {
   string commandSpecification = getUserCommandSpecification();
   Command* cmd = new Command(commandSpecification);
   cmd -> execute();
}
...
Run Code Online (Sandbox Code Playgroud)

Ben*_*son 45

是的,由于new Command(...)没有,C++版本泄漏delete.当然,它可以很容易地编码,以避免这种情况:

...
while (true) {
   string commandSpecification = getUserCommandSpecification();
   Command cmd(commandSpecification);
   cmd.execute();
}
...
Run Code Online (Sandbox Code Playgroud)

......所以我不确定这个例子是否像他们想象的那样具有指导性.

  • 这对于从Java到C++的人来说是一个重要的教训:你应该尽可能避免使用`new`.如果你必须使用`new`,请考虑使用其中一种智能指针类型来确保最终清理. (14认同)
  • @ caleb.breckon:`cmd`可能已经分配了部分(就像它上面的`string`)但是它的分配/释放是按范围进行的,所以当`cmd`超出范围时(在每个循环迭代结束时) )它的析构函数被调用,因此它可以释放`cmd`中任何已分配的部分.但是,`cmd`的实例本身就在堆栈中. (11认同)
  • 新的应该主要用于动态分配.例如,如果您在运行时之前无法知道对象的大小.是的,我遇到了一个由Java程序员编写的C++项目.那太差了.每行代码几乎都有一个新的代码.Java程序员应该真正了解Java和C++之间的区别 (2认同)

xxb*_*bcc 18

C++代码创建了无数个Command永不删除的对象.在C++中没有垃圾收集.必须调用delete由创建的所有实例new.

  • 或者只是使用堆栈 (2认同)

use*_*430 13

使用原始指针已经过时了.如前所述,这是不必要的.如果实际需要指针,请使用std :: unique_ptr.

while (true) {
   string commandSpecification = getUserCommandSpecification();
   std::unique_ptr<Command> cmd(new Command(commandSpecification));
   cmd -> execute();
}
Run Code Online (Sandbox Code Playgroud)

这里没有内存泄漏.


Ini*_*eer 6

由于内存泄漏,C++示例将崩溃.

Command* cmd = new Command(commandSpecification);
Run Code Online (Sandbox Code Playgroud)

在没有相应的情况下连续调用delete.


ehu*_*ang 6

在C++中,没有垃圾收集(范围内的本地除外).因此,C++不断地Command在堆上分配对象,而不需要通过调用释放该内存delete.因此,C++程序最终会耗尽内存.

在Java中,垃圾收集器将看到堆上的对象不再被引用并释放它们,从而避免了内存不足错误.

  • 我会在你的答案的范围内重写_除了本地人 - 在C++中没有垃圾收集,句号.通过编译器生成的代码简单地删除本地:删除具有析构函数的实例,然后将堆栈指针简单地设置回调用之前的位置(忽略可能的返回值).根据该术语的通用含义,这不是垃圾收集. (12认同)
  • C++势脚有时称之为"垃圾预防";) (2认同)