我对此有点困惑:
int *pointer = new int[100]; // Yes
int array [] = new int[100]; // No
但:
unique_ptr<int*> pointer { new int[100] }; // No
unique_ptr<int[]> array { new int[100] }; // Yes
有人可以解释这里涉及的一般原则。我不完全理解为什么智能指针语义似乎与常规原始指针相反。
我对此有点困惑:
int *pointer = new int[100]; // Yes
int array [] = new int[100]; // No
但:
unique_ptr<int*> pointer { new int[100] }; // No
unique_ptr<int[]> array { new int[100] }; // Yes
有人可以解释这里涉及的一般原则。我不完全理解为什么智能指针语义似乎与常规原始指针相反。
智能指针是库代码,因此它们以它们的方式工作,因为有人以这种方式设计它们。
在您的第一个裸数组新代码中,第二行在语法上没有意义,因为您无法使用指针初始化数组并new
返回一个指针。
这个unique_ptr
例子也是错误的;更正后的版本更有意义:
// +--------------+------------ pointer to int
// V V
std::unique_ptr<int> p { new int; }
std::unique_ptr<int[]> p { new int[10]; }
// ^ ^
// +----------------+---------- pointer to first element
// of an array of int
发现模式?
您需要不同模板特化的原因是您需要根据指针的分配方式调用delete
或调用delete[]
指针,但仅通过查看原始指针无法判断。(此外,数组版本提供了一个方便的[]
- 运算符。)
没有什么能阻止你混合unique_ptr<int>
and new int[10]
,但它或多或少是一个微妙的错误,会导致无声的未定义行为(另一个理由是永远不要使用new
你自己,而是依赖make_unique
!)。相比之下,您的第一个示例是一个简单的语法错误。
我 100% 同意 Kerrek SB 的回答。在这里,我只想添加另一个强大的可能性。您还可以定义自定义删除器类
auto deleter= [](int* ptr){delete[] ptr;};
std::unique_ptr<int, decltype(deleter)> ptr4(new int[100], deleter);
这看起来很复杂,但如果您需要调用一些需要 C 结构的堆分配的 C 库,它可能会非常有用
具体示例:GSL GNU 科学库。集成例程需要分配一个名为“gsl_integration_workspace”的结构。在这种情况下,您可以使用以下代码来确保您的代码是异常安全的
auto deleter= [](gsl_integration_workspace* ptr) {
gsl_integration_workspace_free(ptr);
};
std::unique_ptr<gsl_integration_workspace, decltype(deleter)> ptr4 (
gsl_integration_workspace_alloc (2000), deleter);
正如 Kerrek SB 所说,因为智能指针是库代码,所以它们提供了比原始指针更强大的内存管理方式。