我一直在尽力学习C ++,但我之前的培训在一个主要问题上是不足的:内存管理。我的主要语言都有自动垃圾收集,所以跟踪一切从来没有真正必要。我已经尝试过在线阅读C ++中的内存管理,但我对此感到怀疑,认为我很遗憾。
所以,这是一个多部分的问题:
delete
之前循环重新迭代。它是否正确?你需要对引用做些什么吗?malloc
free
calloc
realloc
***********************更新*******************
这是为了解释在评论一中对lmgtfy的引用(由Ewan提供)。如果您开始阅读那里可用的信息,则对初学者没用。我认为这是一个伟大的理论,但它对这个问题既不相关也不有用。
答案 0 :(得分:24)
你真的,真的需要读一本好书 - 坦白地学习C ++是不可能的。我推荐Accelerated C++,作者:Koenig& Moo,C ++的两个创始人。
答案 1 :(得分:15)
_
int* data1 = new int(5);
delete data1;
int* data2 = new int[5];
delete [] data2;
throwing exceptions out of a destructor
Dynamically allocating an array of objects
Pattern name for create in constructor, delete in destructor (C++)
Smart Pointers: Or who owns you baby?
What are the principles guiding your exception handling policy?
// Every new is matched by a delete.
for(int loop = 0;loop < 10;++loop)
{
data = new int(5);
}
delete data;
// The problem is that every 'use of' new is not matched by a delete.
// Here we allocate 10 integers but only release the last one.
class MyArray
{
// Use RAII to manage the dynamic array in an exception safe manor.
public:
MyArray(int size)
:data( new int[size])
{}
~MyArray()
{
delete [] data;
}
// PROBLEM:
// Ignored the rule of 4.
// The compiler will generate a copy constructor and assignment operator.
// These default compiler generated methods just copy the pointer. This will
// lead to double deletes on the memory.
private:
int* data;
};
// Understand what the properties of the smart pointers are:
//
std::vector<std::auto_ptr<int> > data;
// Will not work. You can't put auto_ptr into a standard container.
// This is because it uses move semantics not copy semantics.
// Gurantee that exceptions don't screw up your object:
//
class MyArray
{
// ... As Above: Plus
void resize(int newSize)
{
delete [] data;
data = new int[newSize];
// What happens if this new throws (because there is not enough memory)?
// You have deleted the old data so the old data so it points at invalid memory.
// The exception will leave the object in a completely invalid state
}
答案 2 :(得分:14)
从最简单的意义上说,您需要了解的内存管理是您需要删除在堆上分配的内存。因此,在创建像MyClass *myClass = new MyClass(x);
这样的对象时,您需要在代码中放置一些位置,使用相应的delete
释放/删除它。这在实践中看起来很容易,但如果没有适当的设计和辅助对象(如共享指针)的使用,这可能会很快变得混乱,尤其是在维护代码和添加功能时。例如,这是一个典型的内存泄漏:
try
{
MyClass *myClass = new MyClass(x);
// Do some stuff can throw an exception
delete myClass;
}
catch(...)
{
// Memory leak on exceptions. Delete is never called
}
或者另一个大内存管理问题是调用错误的删除类型:
int* set = new int[100];
delete set; // Incorrect - Undefined behavior
// delete [] set; is the proper way to delete an array of pointers
帮助自己的常用方法是使用RAII习语。 (Resource Allocation Is Initialization)
以下是使用std库以防止内存泄漏的示例:
try
{
auto_ptr<MyClass> myClass(new MyClass(x));
// Now the heap allocated memory associated with myClass
// will automatically be destroyed when it goes out of scope,
// but you can use it much like a regular pointer
myClass->memberFunction();
}
catch (...)
{
}
auto_ptr
的更多信息可以找到here。如果你可以使用C ++ 11,shared_ptr
是一个强烈推荐的选择,通常比auto_ptr更受欢迎。
答案 3 :(得分:5)
答案 4 :(得分:5)
我需要了解内存管理的最低限度是什么? (要么, 我在哪里可以找到它?
对于每个新内容,都必须有删除
我在哪里可以获得中级和高级知识/教程/等(一旦我完成了&gt;基础知识)?
阅读有效的C ++ ,更有效的C ++ 和有效的STL 。然后google(std::) auto_ptr,(boost::) scoped_ptr和(boost::) shared_ptr
更具体地说:指针和引用之间的性能差异是什么?
由于引用是指针值的副本,我不知道我的头脑,我没有预见到任何大的性能问题。
我听说在循环中,你需要确保在循环重新迭代之前在任何新指针上调用delete。这是对的吗?
是
你需要做一些引用吗?
没有
内存泄漏的一些经典例子是什么?
int * foo() {
...
return new int(...);
}
int main() {
int i = *foo();
...
//the new int() from foo leaks
}
关于以下内容我需要了解什么(我将真正需要使用 他们 - 如果是的话,在哪里?):
首先,您永远不应delete
malloc
指针,永远不要free
使用new
创建指针。通常,这些函数不应出现在c ++代码中。但是,如果你发现自己在c-land ......
malloc:类似于new(在堆上分配内存)
free:类似于delete(堆上的可用内存)
calloc:类似于new + memset(在堆上分配内存,将其设置为零)
realloc:尝试调整内存块的大小,或创建新的内存块并复制旧数据free
旧指针。没有真正的c ++等价物。
googleing可以找到一些简洁的记忆内容(这是拼写的吗?)placement new
答案 5 :(得分:4)
你应该研究smart pointers,在内存管理方面,它们会让你的生活变得更轻松。
答案 6 :(得分:3)
“C和C ++中作为编程概念的内存”这本书非常适合那些不熟悉C / C ++的人。
答案 7 :(得分:2)
从您的列表中,您错过了new
和delete
- 有人说永远不会使用malloc
和free
。
也常常被遗忘delete[]
。
答案 8 :(得分:2)
最重要的是要始终如一地勤奋和纪律。对于任何语言的任何资源,甚至更安全的托管语言都是如此。人们认为,当一种语言为他们管理记忆时,他们不必考虑它。但是在完成它们之后,最好尽快释放任何资源。我一直觉得“垃圾收集”近年来让程序员变得懒惰。
当我用c ++之类的语言分配内存时,我确保在使用它之前首先解除分配。换句话说,我写了分配,然后解除分配,然后填写中间。养成一致的习惯很重要。我认为这是最低限度的学习......适当和有纪律的资源管理。这不仅仅是关于内存,它应该应用于所有资源,包括数据库引用,文件引用,上下文句柄和其他此类动物。
C ++中的整个内存管理主题相当广泛。我会尽可能地说阅读,学习和编码。
示例:
char* myusedmemory;
myusedmemory = (char *)malloc(1000); // allocate memory
free(myusedmemory); // immediately deallocate memory
/* go back and fill in the code between */
有很多很好的参考资料可以提供有关该主题的其他知识。我发现浏览relisoft.com上的教程对我很有帮助,虽然主要的教程是针对Windows的。 Another good reference can be found here.
就指针和引用之间的差异而言,主要区别之一是灵活性。你必须立即定义引用(int iExample; int&amp; refExample = iExample;)我不认为会有很多性能差异。但是,更强大,更灵活的指针将更加危险,并且需要上述规则来管理。
examples of memory leaks are here。但你可以通过谷歌搜索“C ++内存泄漏”找到更多信息
就malloc,free,calloc,realloc而言,这些只是函数,就像其他任何命令一样,在这些特殊情况下,stdlib中包含的函数。您应该只了解它们的作用以及如何使用它们,就像使用任何其他函数一样,就像常见的printf()一样。
作为注释:Smart pointers是一种非常好的方式,通常更安全。
作为另一个注释,我想提及Code Complete,这是我读过的关于资源管理主题的最好的书。我已经阅读了很多次的封面。
答案 9 :(得分:2)
在其他语言中,您必须使用诸如“finally”(在Java中)或“使用”(在C#中)之类的机制来跟踪数据库连接,窗口句柄,套接字等。在C ++中,只需向该列表添加内存即可。它在概念上并没有任何不同。
答案 10 :(得分:1)
这是经常捕获学生的东西:大型的,非常大的对象,如数组,应该在动态内存中分配(即使用new
)。
另外,不要传递大型物体。将指针,优选的智能指针传递给对象。复制大对象会占用大量处理器时间。
设置并记录有关对象分配和所有权的规则。被调用者或调用者是否拥有该对象?
不要返回对本地对象的引用,也不要返回指向本地对象的指针。
答案 11 :(得分:1)
了解RAII。这里的一些人指出了这一点,但同时解释了新的/删除的东西,没有强调RAII的重要性。使用RAII,您不必担心内存管理。
对C ++不熟悉的人,往往像Java一样编写代码,随处可见“新”。在许多情况下这是一个坏习惯,在某些情况下你无法避免它(但从我的项目经验来看,这很可能永远不会)。
只需添加此评论即可强调它;)但是所有评论都是完全正确的。
答案 12 :(得分:1)
每个人都提到新的和删除,但大多数时候,你不需要也不应该明确地使用它们:
当然,出于性能原因,您可能希望在性能关键时刻偶尔使用新的和删除对,但这应该是例外而不是规则。
答案 13 :(得分:0)
new
和delete
是内存管理最重要的两个关键字。最简单的是,您只需要记住为您调用delete
的每个对象调用new
。因此,如果您在循环中调用new
,则需要确保在每个delete
'ed对象上调用new
。只要将每个指针的副本保存在以后可以删除的地方,就不需要在循环内执行此操作。
malloc
,free
,calloc
和realloc
都可能比您需要担心的更为先进。我想只要记住,如果标准new
/ delete
感觉有限制,他们就在那里。
所有人都说,智能指针可以提供很大的帮助,但有时候知道如何在处理智能指针之前先解决问题的方法很有帮助。
答案 14 :(得分:0)
当我学习C ++时,我发现使用像Valgrind这样的内存分析工具对于帮助查找内存泄漏是不可或缺的。当您从Valgrind运行程序(使用调试符号编译)时,它将识别内存分配的行,但以后永远不会释放。
我使用这些命令行参数:
valgrind --leak-check=yes --num-callers=8 ./myExecutable
请注意,您的程序运行速度比单独运行要慢得多,但通常值得付出努力。