智能指针如何在delete和delete[]之间进行选择
How do smart pointers choose between delete and delete[]?
考虑:
delete new std :: string [2];
delete [] new std :: string;
每个人都知道第一个是错误。如果第二个不是错误,我们就不需要两个不同的运算符。
现在考虑一下:
std :: unique_ptr <int> x (new int [2]);
std :: unique_ptr <int> y (new int);
x
知道使用delete[]
而不是delete
吗?
背景:当我认为指针的数组类型限定将是一个方便的语言功能时,这个问题在我的脑海中浮现。
int *[] foo = new int [2]; // OK
int * bar = new int; // OK
delete [] foo; // OK
delete bar; // OK
foo = new int; // Compile error
bar = new int[2]; // Compile error
delete foo; // Compile error
delete [] bar; // Compile error
不幸的是,他们不知道使用什么删除,因此他们使用delete
。这就是为什么对于每个智能指针,我们都有一个对应的智能数组。
std::shared_ptr uses delete
std::shared_array uses delete[]
所以,你的线路
std :: unique_ptr <int> x (new int [2]);
实际上会导致未定义的行为。
顺便说一句,如果你写
std :: unique_ptr<int[]> p(new int[2]);
^^
那么CCD_ 5将被使用,因为您已经明确地请求了。但是,下面的行仍然是UB。
std :: unique_ptr<int[]> p(new int);
他们不能在delete
和delete[]
之间进行选择的原因是new int
和new int[2]
完全属于同一类型——int*
。
这里有一个相关的问题,在smart_ptr<void>
和smart_ptr<Base>
的情况下,当Base
没有虚拟析构函数时,使用正确的deleter。
没有"神奇"的方法可以检测int*
是否指:
- 单个堆分配的整数
- 堆分配的数组
- 堆分配数组中的整数
类型系统丢失了信息,没有运行时方法(可移植)可以修复它。这令人愤怒,也是C++继承的C中的一个严重设计缺陷(*)(有人说是为了兼容性)。
然而,有一些处理智能指针中数组的方法。
首先,您的unique_ptr
类型不适合处理数组,您应该使用:
std::unique_ptr<int[]> p(new int[10]);
其意味着调用CCD_ 16。我知道有人说要在Clang中实现一个特定的警告,以发现与unique_ptr
的明显不匹配:这是一个实现质量问题(标准只是说它是UB),并不是所有情况都可以在没有WPA的情况下覆盖。
其次,boost::shared_ptr
可以有一个自定义的deleter,如果您将其设计为调用正确的delete[]
运算符,则可以。然而,有一个boost::shared_array
是专门为此设计的。再一次,检测不匹配是一个实现质量问题。std::shared_ptr
也遇到了同样的问题(在ildjarn的评论之后编辑)。
我同意它不好看。这似乎太令人讨厌了,以至于C起源的一个设计缺陷(*)至今仍困扰着我们。
(*)有些人会说,C非常倾向于避免开销,这会增加开销。我有点不同意:毕竟malloc
总是知道块的大小。
来自微软文档:
(部分专用化
unique_ptr<Type[]>
管理分配有new[]
的数组对象,并具有默认的删除器default_delete<Type[]>
,专用于调用delete[] _Ptr
。)
我加了最后两个方括号,看起来像是打字错误,因为没有它们就没有意义。
std::unique_ptr
不适用于数组,因为我引用了最新的增强文档:
通常,
shared_ptr
不能正确地保存指向动态分配的数组。有关该用法,请参见shared_array
。
如果您想对指针数组进行内存管理,您可以根据自己的需求选择几个选项:
- 使用
boost::shared_array
- 使用
boost::shared_ptr
中的std::vector
- 使用类似
boost::ptr_vector
的提升指针容器
Nicolai Josuttis⟶请注意,std::shared_ptr
提供的默认deleter调用delete,而不是delete[]。这意味着只有当共享指针拥有用new创建的单个对象时,才允许使用默认deleter。不幸的是,为数组创建std::shared_ptr
是可能的,但却是错误的:
std::shared_ptr<int>(new int[10]) //error but compiles
因此,如果使用new[]创建对象数组,则必须定义自己的deleter。例如
std::shared_ptr<int> ptr(new int[10],
[](int* p){ delete[] p; });
或
std::shared_ptr<int> ptr(new int[10],
std::default_delete<int[]>());
对我来说,这是最好的解决方案!
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- int(c) 和 c-'0' 之间的区别。C++
- 在cuda线程之间共享大量常量数据
- 运算符C++ "delete []"仅删除 2 个前值
- 在c代码之间共享数据的最佳方式
- Mix_Init和Mix_OpenAudio SDL之间的区别是什么
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- 大小相等但成员数量不同的结构之间的性能差异
- 类与私有变量的其他类之间的线程安全性
- 如何在cpp文件之间切换窗口?在Qt中
- 线程之间的布尔停止信号
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 析构函数和'delete'之间的区别
- "delete p"和"p->~MyClass()"之间的区别
- C++中new[]/delete[]与new/delete之间的差异
- 智能指针如何在delete和delete[]之间进行选择
- 这就是声明构造函数private和声明=delete之间的区别
- 为什么不能使用数组delete括号之间的值?