【问题标题】:Why delete can perform on pointers to const while free cannot?为什么 delete 可以对指向 const 的指针执行而 free 不能?
【发布时间】:2011-08-06 09:01:39
【问题描述】:

我刚刚注意到传递给delete 的指针可以是const 限定的,而那些传递给free 的指针不能。这对我来说真的是一个惊喜。

在 C++ 中,operator delete 的重载应该具有如下签名:

void operator delete(void* p);

但是在参数指针上加const是无效的:

void operator delete(void const* p);

谁能告诉我为什么delete 是这样设计的?

【问题讨论】:

标签: c++ memory-management


【解决方案1】:

free 不应与实际的 C++ 对象一起使用。 free 应该与malloc 一起使用,因此您不应该在使用new 分配的东西上使用free

至于为什么可以delete const 对象,很简单:

const Type *ptr = new Type(...);

现在呢?如果你不能删除它,那么你必须这样做:

delete const_cast<Type*>(ptr);

对象为const 意味着它不能被修改。您不能使对象从一种状态变为另一种状态。删除就是把它扔掉。这意味着它不再以 any 状态存在,无论是原始形式还是其他修改形式。删除是一种存在于对象可变状态之外的操作,很像构造。

从概念上讲,删除既不是 const 也不是非常量。虽然析构函数是非常量函数,但破坏对象的想法完全超出了 const 或非常量的范围。


好的,假设您将operator delete 定义为pointer to const (which is different from a const pointer)

void operator delete(void const* p);

这个函数的第一行是什么? operator delete 的目的是释放由operator new 分配的内存。这将需要戳内存分配堆上的位。为此,您需要一个不指向 const 数据的指针:

void *ptr = const_cast<void*>(p);

Welcome to undefined behavior。虽然 C++ 允许您这样做,但规范非常明确,尝试写入 ptr(或任何基于它的地址)的结果是未定义。你得到了一个 const 指针;外界告诉你不要修改它指向的东西。 C++ 不保证您违反该合同时会发生什么。

由于规范声明这是未定义的行为,并且由于operator delete(在大多数情况下)无法完成其工作修改p指向的内存(或修改基于该地址),然后允许您以这种方式定义operator delete将是愚蠢的规范。这基本上就是将射击自己的脚的想法规范化。

是的,几乎在所有情况下,这都是完全安全的。但是,既然您无论如何都要抛弃 const,为什么还要费心让这个相当可疑的想法摆在首位呢?

【讨论】:

  • 你甚至可以说const Type *ptr = new const Type(...);,在这种情况下const_cast是非法的。
  • 只回答了一半问题
  • @Jens:我没有回答问题的哪一部分?
  • @Jens:我确实从 C++ 的角度给出了答案。在 C++ 中,您不应该在活动对象上使用 free
  • 请注意const pointer is different from a pointer to const。问题和答案都使用了不正确的术语。
【解决方案2】:

free 是 C 函数。它的签名有 20-30 年的历史,从 C 语言中没有 const 的时代开始(也没有 C++ 语言)。 C++ 编译器将free 视为所有其他函数,并且不能让它接受const 指针而不进行强制转换,因为free 可能会更改指向的对象。实际上,它和delete 一样,但C++ 不知道free 用于内存管理。

【讨论】:

    【解决方案3】:

    应用于指针的const修饰符意味着指向的对象不会被修改。

    但是,delete 使该对象永久退出流通。没有人需要关心它被删除后会发生什么。因此,据我们所知,删除可能会修改对象,也可能不会。为什么这有关系?任何读取或写入对象内容的尝试都是未定义的行为。

    另一方面,当您实现自己的delete 时,您可能需要修改垂死的对象。因此需要指针是非常量的。

    【讨论】:

    • 只回答了一半问题
    【解决方案4】:

    一个区别是free是一个库函数,你必须匹配参数类型。当free被添加到C语言中时,没有const关键字,所以甚至不能考虑。

    在 C++ 中,delete p 是由编译器处理的语句。它可以做任何语言设计者想要做的事情,包括不考虑指向的对象是否为const

    从哲学上讲,delete 语句不会修改对象,只会让它消失。

    【讨论】:

      【解决方案5】:

      在 C++ 中,未定义的行为基于实例化对象的 const 性,在访问路径上存在 const 限定符。因此,const_cast 可用于修改 const 限定目标类型指针后面的对象,只要对象未实例化为 const。

      因为 malloc() 实例化非 const 原始数据,所以 free() 获取指向 const 的指针,然后将其丢弃并根据需要修改内存是完全合法的。但是因为 free() 早于 const 关键字,所以它不符合它应有的条件。

      C++ 程序员可能会抛弃 const 以释放 malloc 的内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 2011-01-14
        • 2010-09-18
        • 2022-01-11
        • 1970-01-01
        • 2021-08-09
        • 2015-09-10
        相关资源
        最近更新 更多