正确声明和初始化 unique_ptr 管理数组需使用 std::unique_ptr 形式,并通过 new T[size] 初始化,例如 std::unique_ptr arr(new int[10]);,这样析构时会自动调用 delete[] 释放内存,避免内存泄漏或崩溃。常见错误是使用 std::unique_ptr 管理数组,导致 delete 与 delete[] 不匹配,引发未定义行为。unique_ptr 相比原始指针优势在于自动内存管理、异常安全、明确独占所有权,防止内存泄漏和悬挂指针。C++14 的 std::make_unique 不直接支持数组,但可自定义 make_unique_array 辅助函数实现类似功能。unique_ptr 管理数组时不可复制,所有权转移需使用 std::move,若需共享所有权应使用 std::shared_ptr,并配合自定义删除器或 std::default_delete 确保正确调用 delete[]。

C++的
unique_ptr可以管理动态分配的数组,但需要一些特殊的处理。关键在于使用
unique_ptr,而不是
unique_ptr。这告诉
unique_ptr它管理的是一个数组,析构时会使用
delete[]而不是
delete。
解决方案
使用
std::unique_ptr来管理动态数组。
如何正确声明和初始化 unique_ptr
来管理数组?
立即学习“C++免费学习笔记(深入)”;
声明时使用
unique_ptr,初始化时使用
new T[size]。例如:
#include#include int main() { // 创建一个可以管理 int 数组的 unique_ptr std::unique_ptr arr(new int[10]); // 初始化数组 for (int i = 0; i < 10; ++i) { arr[i] = i * 2; } // 访问数组元素 for (int i = 0; i < 10; ++i) { std::cout << arr[i] << " "; } std::cout << std::endl; // unique_ptr 会自动释放数组内存 return 0; }
如何避免使用 unique_ptr
管理数组时的常见错误?
最常见的错误是使用
unique_ptr而不是
unique_ptr。 这样做会导致析构时调用
delete而不是
delete[],从而导致未定义行为,通常是内存泄漏或程序崩溃。 另一个潜在的问题是忘记初始化数组。虽然
unique_ptr会管理内存,但它不会自动初始化数组中的元素。
例如,以下代码是错误的:
#includeint main() { // 错误:使用了 unique_ptr 来管理数组 // 这会导致 delete 和 delete[] 不匹配 // std::unique_ptr arr(new int[10]); // 编译可以通过,但是运行时会出错 // 正确的做法是 std::unique_ptr arr(new int[10]); return 0; }
为什么 unique_ptr
是管理动态数组的好选择,相比原始指针有什么优势?
unique_ptr提供了自动内存管理,避免了手动
delete[]的需要。 这可以防止内存泄漏和悬挂指针。 此外,
unique_ptr明确了所有权,使得代码更容易理解和维护。 原始指针需要手动管理内存,容易出错。
使用
unique_ptr的优势:
-
自动内存管理:
unique_ptr
在离开作用域时会自动释放内存,无需手动delete[]
。 -
防止内存泄漏: 即使发生异常,
unique_ptr
也能保证内存被释放。 -
明确所有权:
unique_ptr
明确表示对所管理资源的独占所有权。 -
异常安全: 即使在构造或使用数组时抛出异常,
unique_ptr
也能确保资源得到正确释放。
如何使用 std::make_unique
创建 unique_ptr
来管理数组?
C++14 引入了
std::make_unique,但它不直接支持数组的创建。 这是因为
make_unique的设计目的是为了避免
new表达式和构造函数之间的异常安全问题,而对于数组,这个问题的处理方式略有不同。 你仍然需要使用
new T[]来分配数组,然后用
unique_ptr管理。
虽然不能直接使用
make_unique,但可以自己实现一个类似的辅助函数:(size)
#include#include template std::unique_ptr make_unique_array(size_t size) { return std::unique_ptr (new T[size]); } int main() { // 使用辅助函数创建 unique_ptr auto arr = make_unique_array (5); for (int i = 0; i < 5; ++i) { arr[i] = i + 1; std::cout << arr[i] << " "; } std::cout << std::endl; return 0; }
unique_ptr
管理数组时,如何传递和共享所有权?
unique_ptr设计为独占所有权,这意味着只有一个
unique_ptr可以指向特定的资源。 因此,不能直接复制
unique_ptr。 如果需要转移所有权,可以使用
std::move。
#include#include int main() { std::unique_ptr arr1(new int[5]); for (int i = 0; i < 5; ++i) { arr1[i] = i * 3; } // 转移所有权 std::unique_ptr arr2 = std::move(arr1); // 现在 arr1 不再拥有数组的所有权,访问 arr1 会导致未定义行为 // arr1[0] = 10; // 避免这样做 // arr2 现在拥有数组的所有权 for (int i = 0; i < 5; ++i) { std::cout << arr2[i] << " "; } std::cout << std::endl; // arr2 会在离开作用域时释放数组内存 return 0; }
如果需要共享资源,考虑使用
std::shared_ptr。 但是,对于数组,
shared_ptr的使用需要特别小心,确保正确地指定删除器,以使用
delete[]而不是
delete。
#include#include int main() { std::shared_ptr arr(new int[5], [](int* p){ delete[] p; }); for (int i = 0; i < 5; ++i) { arr.get()[i] = i * 5; } for (int i = 0; i < 5; ++i) { std::cout << arr.get()[i] << " "; } std::cout << std::endl; return 0; }
或者使用别名模板,使代码更清晰:
#include#include template using shared_array = std::shared_ptr ; int main() { shared_array arr(new int[5], std::default_delete ()); for (int i = 0; i < 5; ++i) { arr.get()[i] = i * 5; } for (int i = 0; i < 5; ++i) { std::cout << arr.get()[i] << " "; } std::cout << std::endl; return 0; }
总结,
unique_ptr是管理动态数组的强大工具,但需要正确使用
unique_ptr并注意所有权转移。
shared_ptr也可以用于共享数组,但需要小心处理删除器。










