我有点困惑:
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
有人可以解释这里涉及的一般原则。我不完全理解为什么智能指针语义似乎与常规原始指针相反。
答案 0 :(得分: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>
和new int[10]
没有什么,但它是一个或多或少的微妙错误导致静默未定义的行为(另一个原因是永远不会使用{{ 1}}你自己而是依靠new
!)。相比之下,你的第一个例子是一个简单的语法错误。
答案 1 :(得分: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所说,因为智能指针是库代码,所以它们提供了比原始指针更强大的内存管理方式。