当使用std::list<std::string>时,我偶然发现了堆栈溢出问题std::string的内存泄漏,其中一个注释说:
不要用那么多new。我看不出你为什么在任何地方都用新的。你可以在c++中通过值创建对象,这是使用该语言的一个巨大优势。您不必分配堆上的所有内容。不要像Java程序员那样思考。
我不太确定他这么说是什么意思。
为什么在c++中应该尽可能多地根据值创建对象,这在内部有什么不同?我误解了答案吗?
当使用std::list<std::string>时,我偶然发现了堆栈溢出问题std::string的内存泄漏,其中一个注释说:
不要用那么多new。我看不出你为什么在任何地方都用新的。你可以在c++中通过值创建对象,这是使用该语言的一个巨大优势。您不必分配堆上的所有内容。不要像Java程序员那样思考。
我不太确定他这么说是什么意思。
为什么在c++中应该尽可能多地根据值创建对象,这在内部有什么不同?我误解了答案吗?
当前回答
New()不应该尽可能少地使用。应该尽可能小心地使用它。而且,它应该在实用主义的要求下,在必要时经常使用。
对象在堆栈上的分配依赖于它们的隐式销毁,这是一个简单的模型。如果对象所需的作用域符合该模型,则不需要使用new(),以及相关的delete()和NULL指针检查。 在你有很多短期对象的情况下,在堆栈上分配应该可以减少堆碎片的问题。
但是,如果对象的生命周期需要扩展到当前范围之外,那么new()是正确的答案。只要确保您注意何时以及如何调用delete()以及NULL指针的可能性,使用已删除对象以及使用指针所带来的所有其他问题。
其他回答
使用new时,对象被分配到堆中。它通常用于预期扩展时。当你声明一个对象,比如,
Class var;
它被放置在堆栈上。
你总是需要对你用new放在堆上的对象调用destroy。这就有可能导致内存泄漏。放在堆栈上的对象不容易发生内存泄漏!
以上所有正确答案还有一点,这取决于你在做什么类型的编程。在Windows中开发内核,例如->堆栈受到严重限制,您可能无法像在用户模式中那样处理页面错误。
在这样的环境中,新的或类似c的API调用是首选的,甚至是必需的。
当然,这只是规则的一个例外。
两个原因:
在这种情况下没有必要。您正在使代码不必要地变得更加复杂。 它在堆上分配空间,这意味着您必须记住稍后删除它,否则将导致内存泄漏。
在很大程度上,这是某人将自己的弱点提升为普遍准则。使用new操作符创建对象本身没有任何问题。有一些争论是,你必须遵循一些规则:如果你创建了一个对象,你需要确保它会被销毁。
最简单的方法是在自动存储中创建对象,这样c++就知道在它超出作用域时销毁它:
{
File foo = File("foo.dat");
// Do things
}
现在,观察一下,当你在结束大括号之后离开那个块时,foo超出了作用域。c++会自动调用它的析构函数。与Java不同,您不需要等待垃圾回收来找到它。
你写过
{
File * foo = new File("foo.dat");
你需要显式地匹配它
delete foo;
}
或者更好的是,将你的File *分配为“智能指针”。如果你不小心,它可能会导致泄漏。
答案本身做了一个错误的假设,如果你不使用new,你就不会在堆上分配;事实上,在c++中你不知道这一点。最多,您知道少量的内存,比如一个指针,肯定分配在堆栈上。但是,考虑一下File的实现是否像这样:
class File {
private:
FileImpl * fd;
public:
File(String fn){ fd = new FileImpl(fn);}
然后FileImpl仍然会被分配到堆栈上。
是的,你最好确保你有
~File(){ delete fd ; }
在课堂上也是如此;如果没有它,即使根本没有在堆上分配内存,也会从堆中泄漏内存。
原因很复杂。
首先,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 */ }
明白了吗?