当使用std::list<std::string>时,我偶然发现了堆栈溢出问题std::string的内存泄漏,其中一个注释说:
不要用那么多new。我看不出你为什么在任何地方都用新的。你可以在c++中通过值创建对象,这是使用该语言的一个巨大优势。您不必分配堆上的所有内容。不要像Java程序员那样思考。
我不太确定他这么说是什么意思。
为什么在c++中应该尽可能多地根据值创建对象,这在内部有什么不同?我误解了答案吗?
当使用std::list<std::string>时,我偶然发现了堆栈溢出问题std::string的内存泄漏,其中一个注释说:
不要用那么多new。我看不出你为什么在任何地方都用新的。你可以在c++中通过值创建对象,这是使用该语言的一个巨大优势。您不必分配堆上的所有内容。不要像Java程序员那样思考。
我不太确定他这么说是什么意思。
为什么在c++中应该尽可能多地根据值创建对象,这在内部有什么不同?我误解了答案吗?
当前回答
原因很复杂。
首先,c++不进行垃圾收集。因此,对于每一个new,必须有一个对应的delete。如果您没有将此删除,那么您就有内存泄漏。现在,对于这样一个简单的例子:
std::string *someString = new std::string(...);
//Do stuff
delete someString;
这很简单。但是如果“Do stuff”抛出异常会发生什么?哎呀:内存泄漏。如果“做事情”问题提前回归会发生什么?哎呀:内存泄漏。
这是最简单的情况。如果你碰巧将这个字符串返回给某人,现在他们必须删除它。如果他们把它作为参数传递,接收它的人需要删除它吗?什么时候删除?
或者,你可以这样做:
std::string someString(...);
//Do stuff
没有删除。对象是在“堆栈”上创建的,一旦超出作用域就会被销毁。您甚至可以返回对象,从而将其内容传递给调用函数。你可以将对象传递给函数(通常作为引用或const-reference: void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis)。等等。
全部不需要new和delete。不存在谁拥有内存或谁负责删除它的问题。如果你有:
std::string someString(...);
std::string otherString;
otherString = someString;
可以理解为otherString拥有someString数据的副本。它不是指针;它是一个单独的对象。它们可能碰巧具有相同的内容,但你可以在不影响另一个的情况下更改其中一个:
someString += "More text.";
if(otherString == someString) { /*Will never get here */ }
明白了吗?
其他回答
使用new时,对象被分配到堆中。它通常用于预期扩展时。当你声明一个对象,比如,
Class var;
它被放置在堆栈上。
你总是需要对你用new放在堆上的对象调用destroy。这就有可能导致内存泄漏。放在堆栈上的对象不容易发生内存泄漏!
新就是新目标。
Recall why goto is so reviled: while it is a powerful, low-level tool for flow control, people often used it in unnecessarily complicated ways that made code difficult to follow. Furthermore, the most useful and easiest to read patterns were encoded in structured programming statements (e.g. for or while); the ultimate effect is that the code where goto is the appropriate way to is rather rare, if you are tempted to write goto, you're probably doing things badly (unless you really know what you're doing).
New也类似——它经常被用来使事情变得不必要的复杂和难以阅读,最有用的使用模式可以被编码到各种各样的类中。此外,如果您需要使用任何新的使用模式,而这些模式还没有标准类,您可以编写自己的类来编码它们!
我甚至认为new比goto更糟糕,因为需要对new和delete语句进行配对。
像goto一样,如果您认为需要使用new,那么您可能做得很糟糕——特别是如果您在一个类的实现之外这样做,这个类的目的是封装您需要做的任何动态分配。
核心原因是堆上的对象总是比简单值更难使用和管理。编写易于阅读和维护的代码始终是任何认真的程序员的首要任务。
另一种情况是,我们使用的库提供了值语义,使动态分配变得不必要。Std::string就是一个很好的例子。
然而,对于面向对象的代码,使用指针——这意味着使用new来预先创建指针——是必须的。为了简化资源管理的复杂性,我们有几十种工具使其尽可能简单,比如智能指针。基于对象的范式或泛型范式假设值语义,并需要更少或不需要新的,正如其他地方的海报所述。
传统的设计模式,尤其是GoF书中提到的那些,大量使用new,因为它们是典型的面向对象代码。
C++ doesn't employ any memory manager by its own. Other languages like C# and Java have a garbage collector to handle the memory C++ implementations typically use operating system routines to allocate the memory and too much new/delete could fragment the available memory With any application, if the memory is frequently being used it's advisable to preallocate it and release when not required. Improper memory management could lead memory leaks and it's really hard to track. So using stack objects within the scope of function is a proven technique The downside of using stack objects are, it creates multiple copies of objects on returning, passing to functions, etc. However, smart compilers are well aware of these situations and they've been optimized well for performance It's really tedious in C++ if the memory being allocated and released in two different places. The responsibility for release is always a question and mostly we rely on some commonly accessible pointers, stack objects (maximum possible) and techniques like auto_ptr (RAII objects) The best thing is that, you've control over the memory and the worst thing is that you will not have any control over the memory if we employ an improper memory management for the application. The crashes caused due to memory corruptions are the nastiest and hard to trace.
我倾向于不同意使用new“too much”的观点。尽管最初的海报使用new with system classes有点可笑。(int *我;I = new int[9999];?真的吗?int [9999];这样就清楚多了。)我想这就是让评论者生气的地方。
When you're working with system objects, it's very rare that you'd need more than one reference to the exact same object. As long as the value is the same, that's all that matters. And system objects don't typically take up much space in memory. (one byte per character, in a string). And if they do, the libraries should be designed to take that memory management into account (if they're written well). In these cases, (all but one or two of the news in his code), new is practically pointless and only serves to introduce confusions and potential for bugs.
When you're working with your own classes/objects, however (e.g. the original poster's Line class), then you have to begin thinking about the issues like memory footprint, persistence of data, etc. yourself. At this point, allowing multiple references to the same value is invaluable - it allows for constructs like linked lists, dictionaries, and graphs, where multiple variables need to not only have the same value, but reference the exact same object in memory. However, the Line class doesn't have any of those requirements. So the original poster's code actually has absolutely no needs for new.