返回

使用unique_ptr处理已分配数组时避免内存泄漏和未定义行为

Linux

如何使用 unique_ptr 正确处理已分配数组

背景

unique_ptr 是一个非常有用的 C++ 标准库类,它使我们能够管理指向自由存储器分配对象的唯一指针。然而,当我们尝试使用 unique_ptr 来管理动态分配的数组时,可能会遇到内存泄漏和未定义行为。

问题

问题在于 unique_ptr 的析构函数会调用 std::default_delete<unsigned char>,而该函数预期的是一个指向单个元素的指针,而不是一个指向数组第一个元素的指针。这会导致 Valgrind 报告内存泄漏和未定义行为。

解决方案

解决此问题的正确方法是使用 make_unique 函数来创建 unique_ptrmake_unique 函数能够正确处理数组的情况,它会生成一个指向数组第一个元素的 unique_ptr,并确保在 unique_ptr 的析构函数中正确调用 delete[] 来释放数组。

以下是如何使用 make_unique 函数创建 unique_ptr 的示例代码:

#include <memory>
#include <string.h>

using namespace std;

int main()
{
    unique_ptr<unsigned char[]> testData = make_unique<unsigned char[]>(16000);

    memset(testData.get(), 0x12, 0);

    return 0;
}

总结

要正确创建持有在自由存储器上分配的数组的 unique_ptr,请使用 make_unique<unsigned char[]>(16000)。这将确保 unique_ptr 的析构函数以正确的方式释放数组。

常见问题解答

  • 为什么在使用 Visual Studio 2013 时没有这个问题?
    Visual Studio 2013 的标准库有一个错误,它允许 unique_ptr 正确处理数组。在较新的编译器中,此错误已得到修复。

  • 为什么 std::default_delete<unsigned char> 期望一个指向单个元素的指针?
    std::default_delete 是一个通用函数,它可以删除任何类型的对象。但是,它假设被删除的对象是一个单个元素,而不是一个数组。

  • 我可以使用 new 运算符直接创建 unique_ptr 来处理数组吗?
    不可以。new 运算符无法生成指向数组的 unique_ptr。必须使用 make_unique 函数。

  • 除了 make_unique,还有其他方法来解决此问题吗?
    有,但是 make_unique 是最简单、最可靠的方法。

  • 何时应该使用 make_unique 来创建 unique_ptr
    应该始终使用 make_unique 来创建持有动态分配对象的 unique_ptr,无论该对象是单个元素还是数组。