我只知道内存泄漏的正式含义,如果我们不使用关键字'delete'来删除指针。但是,当我们以下列方式执行时,为什么有泄漏的可能性?
void k()
{
vector<m*>p;
:
:
:
}
据我所知,删除指针是由编译器自动完成的,所以我们真的有必要删除指针吗?
答案 0 :(得分:3)
据我所知,删除指针是由编译器自动完成的
不,不是。以下是泄漏:
vector<m*>p;
p.push_back(new m);
您需要自己删除内存:
delete p[0]; //in this case
干净的选择是使用智能指针:
vector<std::shared_ptr<m> > p;
答案 1 :(得分:3)
这取决于您放入p
的内容。如果你只存储指向其他地方管理的东西(或者没有动态分配的东西)的指针,那么就没有泄漏:vector
的内容将被析构函数清理。
但是,如果您执行p.push_back(new m);
之类的操作,并且在delete
退出之前永远不会在p
的元素上调用k
,那么您确实会泄漏内存。 vector
(指针)的内容将被析构函数清理掉;指针指向的内存不会。
答案 2 :(得分:2)
假设您分配了向量的内容(m*
s)与new
,将需要如果您想避免泄漏,请在退出该功能之前自己执行delete
。仅当内容是对象时,自动删除矢量内容才能很好地工作,而不是指向动态分配对象的指针。
您可以做的是将m*
替换为std::unique_ptr<m>
。现在,智能指针将自动执行delete
,您无需执行任何操作。
vector<std::unique_ptr<m>>p;
或者,这也是安全的。由于您按值存储,因此当离开函数时,向量析构函数将自动销毁内容。
vector<m>p;
答案 3 :(得分:2)
只是为了解决您的初始问题:存在两种相关但不同的内存管理错误概念。我喜欢Valgrind使用的术语,这是一个流行的内存调试器:
仍然可以访问的内存:这不是严格意义上的泄漏,而只是程序员的一部分懒惰。这是不洁净的,但不一定是个问题。当您只是不打算清理可以清理的东西时会发生这种情况:
int main()
{
int * p = new int[100];
}
// memory at p is still reachable
在这样的代码中,“仍然可以访问”的分配通常在程序结束之前使用,并且唯一合理的清理点将在最后。
绝对丢失内存:这是你真正的泄漏。当您丢失对动态分配的内存的所有引用时,会发生这种情况这意味着即使在原则上你也无法释放这些资源。这是一个严重的编程错误。如果你在一个循环中泄漏内存,或者在一个被称为任意次数的东西中泄漏,你的程序很可能只是在它运行了太长时间后才会死掉,可能不会在其余的操作系统暂时无法使用之前。典型代码如下所示:
int foo()
{
int * p = new int[100]();
return p[20] + 2;
} // leak: We lost track of the memory at p
int main()
{
for (std::string line; std::getline(std::cin, line); )
{
int * q = new int[line.length() + 1];
q[0] = foo(); // leak 1
} // leak 2: lost track of the memory at q
}
上述所有情况都违反了记忆管理的基本规则,该规则首先在13世纪制定:
CPU,让我成为你代码的工具 如果有
malloc
,请写下free
哪里有new
,delete
。
哪里有new[]
,delete[]
。
输入
作为推论,我们可以推断出 C ++内存管理的黄金法则,它可以大大降低内存管理漏洞的风险:
请勿使用
new
,切勿使用delete
。不要使用原始指针。
关键是原始指针不带有关于可能的指针的任何所有权信息。因此,仅基于原始指针来决定是否以及如何进行任何清理是不可能的。这也是你的代码的问题 - 答案很简单,“它取决于”!
答案 4 :(得分:0)
矢量本身很好。它会自动正确地管理自己的内存。
因此答案取决于你在该载体中放置的内容。如果将指针放在堆分配的对象上,则在完成这些对象时,您有责任释放这些对象。向量不会为你做那个。
如果你没有这样做,你就会有内存泄漏。
答案 5 :(得分:0)
当您从该向量中移除元素时(使用resize
,erase
或clear
),并假设m*
已分配new
,它将会不要使用delete
运算符。因此,您将有内存泄漏。但是,如果这些指针指向堆栈上的变量,则不会发生内存泄漏。
编辑: 您可以在从向量中删除元素之前删除元素,但是如果您调用调整大小或清除,则很可能不会删除所有元素(除非您在清除之前循环和删除)。
答案 6 :(得分:0)
删除向量时,不会删除向量中的指针。你可以使用
vector<shared_ptr<m>> p
如果您与程序的其他部分共享指针。
答案 7 :(得分:0)
表面上的答案是否定的:你没有分配任何记忆
你的片段,所以没有泄漏。
一个更有用的答案是:它取决于角色的作用
vector
是,以及你投入的内容。
对于初学者,如果类型m
具有值语义,则为
可复制,您应该使用vector<m>
,而不是vector<m*>
。
当然,vector<m>
没有泄漏的可能
(假设您已正确实施m
)。
使用指针向量的最常见原因,at 至少在我工作的应用领域中,是为了 实体对象之间的导航。每个实体对象都管理 它自己的一生,或(不太常见),属于其他一些 实体对象将管理其生命周期。所以没有 泄漏的风险但存在非常大的风险 一个悬空指针:指向一个物体的生命周期 结束,你必须确保从中删除任何指向它的指针 矢量。 (这通常是通过使用的一些变体来完成的 观察者模式。)
使用指针向量的另一个原因是
包含的对象是多态的,或者是大而且昂贵的
复制。在这种情况下, if 包含的对象不包含
指针,或者你可以证明周期是
不可能,和指向的对象没有重要意义
内部行为(因此this
)的使用非常有限,
你可以制作一个std::shared_ptr<m>
的集合;在
实践中,Boost的指针容器可能更好
解决方案(并避免std::shared_ptr
的风险)。这俩
shared_ptr
解决方案和Boost的指针容器需要
将动态分配向量中的所有元素。