4

我对此有点困惑:

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

有人可以解释这里涉及的一般原则。我不完全理解为什么智能指针语义似乎与常规原始指针相反。

4

2 回答 2

5

智能指针是库代码,因此它们以它们的方式工作,因为有人以这种方式设计它们。

在您的第一个裸数组新代码中,第二行在语法上没有意义,因为您无法使用指针初始化数组并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!)。相比之下,您的第一个示例是一个简单的语法错误。

于 2013-08-31T00:45:25.497 回答
2

我 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 所说,因为智能指针是库代码,所以它们提供了比原始指针更强大的内存管理方式。

于 2013-08-31T01:15:44.013 回答