awi*_*ebe 125 c++ syntax standards memory-management language-lawyer
每次有人delete[]在这里问一个问题时,总会有一个非常笼统delete[]的回答:“ C++ 就是这样做的,使用”。来自普通的 C 背景,我不明白为什么需要一个不同的调用。
使用malloc()/free()您的选择是获取指向连续内存块的指针并释放连续内存块。实现领域中的某些东西会根据基地址知道您分配的块的大小,以便您何时必须释放它。
没有功能free_array()。我在与此相关的其他问题上看到了一些疯狂的理论,例如调用delete ptr只会释放数组的顶部,而不是整个数组。或者更正确的是,它不是由实现定义的。当然……如果这是 C++ 的第一个版本,并且您做出了一个有意义的奇怪设计选择。但是为什么 with$PRESENT_YEAR的 C++ 标准没有被重载???
似乎 C++ 添加的唯一额外的一点是遍历数组并调用析构函数,我认为这可能是它的症结所在,它实际上是使用一个单独的函数来为我们节省单个运行时长度查找,或者nullptr在列表的末尾,以换取折磨每个新的 C++ 程序员或程序员,他们有一个模糊的一天并且忘记了有一个不同的保留字。
如果除了“这就是标准所说的并且没有人质疑它”之外还有其他原因,有人可以一劳永逸地澄清吗?
Fra*_*eux 169
C++ 中的对象通常具有需要在其生命周期结束时运行的析构函数。delete[]确保调用数组每个元素的析构函数。但是这样做有未指定的开销,而delete没有。一种用于数组,它支付开销,另一种用于不支付开销的单个对象。
为了只有一个版本,实现需要一种机制来跟踪有关每个指针的额外信息。但是 C++ 的创始原则之一是用户不应该被迫支付他们绝对不必支付的成本。
永远delete是你new,永远delete[]是你new[]。但在现代C ++,new和new[]一般不再使用。使用std::make_unique,std::make_shared,std::vector或其他更富有表现力和更安全的替代品。
mil*_*bug 41
基本上,malloc和free分配内存,并new与delete创建和销毁对象。所以你必须知道对象是什么。
要详细说明 François Andrieux 的回答提到的未指定开销,您可以查看我对这个问题的回答,其中我检查了特定实现的作用(Visual C++ 2013,32位)。其他实现可能会也可能不会做类似的事情。
如果new[]与具有非平凡析构函数的对象数组一起使用,它所做的是多分配 4 个字节,并返回前移 4 个字节的指针,因此当delete[]想知道那里有多少对象时,它需要指针,先将其移动 4 个字节,然后获取该地址处的数字并将其视为存储在那里的对象数。然后它在每个对象上调用一个析构函数(从传递的指针的类型知道对象的大小)。然后,为了释放确切的地址,它传递了传递地址之前 4 个字节的地址。
在这个实现中,将分配的数组传递new[]给常规会delete导致调用第一个元素的单个析构函数,然后将错误的地址传递给释放函数,从而破坏堆。不要这样做!
dav*_*bak 34
东西不是在其他(都好)的答案中提到的是,这一现象的根本原因是阵列-由C继承-从来没有在C“一流”的事情++。
它们具有原始的 C 语义,没有 C++ 语义,因此没有 C++ 编译器和运行时支持,这将使您或编译器运行时系统使用指向它们的指针做有用的事情。
事实上,C++ 不支持它们,以至于指向一组事物的指针看起来就像指向单个事物的指针。特别是,如果数组是语言的适当部分,则不会发生这种情况——即使是作为库的一部分,如字符串或向量。
C++ 语言的这个问题是由于 C 的这种传统而发生的。它仍然是语言的一部分 - 即使我们现在有std::array固定长度的数组和(一直有)std::vector可变长度的数组 - 主要是为了兼容性:能够从 C++ 调用操作系统 API 和使用 C 语言互操作的其他语言编写的库。
而且……因为有大量书籍、网站和教室在他们的 C++ 教学法中很早就教授数组,因为 a) 能够在早期编写有用/有趣的示例,这些示例实际上调用了 OS API,当然因为 b) “这就是我们一直这样做的方式”的惊人力量。
通常,C++ 编译器及其关联的运行时构建在平台的 C 运行时之上。特别是在这种情况下 C 内存管理器。
C 内存管理器允许您在不知道内存大小的情况下释放内存块,但是没有标准方法可以从运行时获取块的大小,并且无法保证实际分配的块大小与您的大小完全相同。要求。它可能更大。
因此,由 C 内存管理器存储的块大小不能有效地用于启用更高级别的功能。如果更高级别的功能需要有关分配大小的信息,那么它必须自己存储它。(delete[]对于带有析构函数的类型,C++确实需要它,以便为每个元素运行它们。)
C++ 也有一种“你只为你使用的东西付费”的态度,为每个分配存储一个额外的长度字段(与底层分配器的簿记分开)不适合这种态度。
由于在 C 和 C++ 中表示未知(在编译时)大小的数组的正常方法是使用指向其第一个元素的指针,因此编译器无法根据类型区分单个对象分配和数组分配系统。所以它留给程序员来区分。
| 归档时间: |
|
| 查看次数: |
9702 次 |
| 最近记录: |