不使用new关键字,我是否可能存在内存泄漏?

12

我对这门语言还很陌生,关于内存泄漏我有一个基本问题。 如果我没有使用new关键字(例如将变量存储在堆栈中并使用数据容器如std::vector),是否可能出现内存泄漏?

我应该担心这个问题吗?

如果是这种情况,是否有人可以举例说明一种不需要动态分配内存却会导致泄漏的情况?


2
基本上,“不”。 - user2100815
2
假设您也不使用malloc,呵呵。 - Phil M
1
@Phil "不使用动态分配内存" - user2100815
1
@DeiDei "不使用动态分配内存" - user2100815
4
您可以通过以下方式获取泄漏,具体描述请参考此处 - NathanOliver
显示剩余6条评论
3个回答

7

即将我的变量放在堆栈中,并使用数据容器如std::vector

不,使用std::vector或其他标准容器就不需要担心这个问题。

有人能给我举一个不涉及动态分配内存的内存泄漏情况的例子吗?

一种常见的错误是循环依赖的智能指针,形式如下:

class Child;
class Parent {
     std::vector<std::shared_ptr<Child>> childs;
};

class Child {
     std::shared_ptr<Parent> parent;
};

由于共享指针的引用计数永远不会降至零,这些实例永远不会被删除,从而导致内存泄漏。

有关导致此问题以及如何避免它的更多信息,请参见此处


4

除了其他答案外,内存泄漏的另一个容易出现的来源是外部库。很多库,特别是类似于C语言的库,有像create_*destroy_*这样针对数据类型的函数。即使您从未显式调用new,仍然很容易出现内存泄漏。


1
避免这个问题的个人建议是将类型封装在一个简单的RAII类中,或者使用带有自定义删除器的std::unique_ptr - sudgy

4
如果您不动态地分配内存,则不可能泄漏内存。也许全局变量不会被释放,但我不会称之为内存泄漏。
然而,有比使用关键字 "new" 更多的动态分配内存的方法。
例如,malloc 分配一个内存块。此外,calloc 分配一段内存并将其清零。
您的操作系统还可以提供管理内存的方法。例如在 Linux 中使用 strdup
您还可以使用智能指针,并调用 std::make_uniquestd::make_shared。两种方法都是动态分配内存。
对于 std::unique_ptr,如果调用了 release() 并忘记删除指针,则可能会泄漏内存。
 std::make_unique<int>(3).release(); // Memory leak

对于std::shared_ptr,如果创建循环引用,可能会导致内存泄漏。您可以在这里找到更多信息。
此外,当使用静态变量时,析构函数不会在变量离开作用域时调用,而是在执行结束时调用。这不完全是内存泄漏,因为最终会调用析构函数,但您可能会有一些已分配但未使用的内存。
例如,请考虑以下代码:
#include <iostream>
#include <string>
#include <vector>

void f() 
{
    static std::vector<int> v;
    v.insert(v.begin(), 100*1024*1024, 0);
    v.clear();
}

int main()
{
    f();
    return 0;
}

std::vector::clear() 不需要释放向量分配的内存。因此,在调用 f() 后,您将有400 MB的内存分配,但只能在 f() 内部访问。这不完全是内存泄漏,但它是一种资源分配,直到结束时才会自动释放。


非常好。感谢您提供的示例,特别是最后一个,我想我可能犯了那个错误! - MonkeyCoder
3
拥有一个静态向量并没有什么问题。但这并不是一个特别好的答案。 - user2100815
1
@Neil 拥有一个静态向量是可以的。但是,如果你只推入元素而从不弹出它们,那么它只会增长而永远不会被删除。 - J. Calleja
@J.Calleja 析构函数将在程序正常退出时被调用。 - user2100815
你说得对。析构函数会在最后被调用。这只是一个简化的例子,我们创建了一个静态向量并使其增长直到内存耗尽。我会更新答案。 - J. Calleja
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接