通过指向常量的指针释放内存是一种好习惯吗

Posted

技术标签:

【中文标题】通过指向常量的指针释放内存是一种好习惯吗【英文标题】:Is it a good practice to free memory via a pointer-to-const 【发布时间】:2010-02-18 11:45:19 【问题描述】:

有很多问题讨论了 C 和 C++ 处理指针到 const 删除的细节,即 free() 不接受它们,deletedelete[] 接受并且 constness 不会阻止对象破坏。

我感兴趣的是您是否认为这样做是一种好习惯,而不是语言(C 和 C++)所允许的。

指针到常量删除的参数包括:

Linus Torvalds 的 kfree() 与 C 的 free() 不同,它采用 void const* 参数,因为他认为释放内存不会影响指向的内容。 free() 是在引入 const 关键字之前设计的。 C++ 的删除运算符允许删除 const 数据。

反对它的论据包括:

程序员在将指向 const 的指针传递给数据时,并不期望数据会被修改(或删除)。 许多人认为指向 const 的指针意味着不获得数据的所有权(但不是非 const 意味着获得所有权)。 这是大多数库和现有代码中常见的做法。

请在你的回答中好好论证,并可能参考权威机构。我的目的不是在这里发起投票。

【问题讨论】:

对我来说,接受一个 non-const 指针意味着一个 out 参数。如果不是更新对象而是销毁它,我会同样感到惊讶。 @nobugz 很多有价值的“最佳实践”问题(在某种程度上)不是主观的,因为答案(如果有的话)很大程度上取决于实践/偏好的统计分布(等等, 意见)? @visitor,通过非常量指针参数转移所有权是很常见的。所有智能指针都在其构造函数和可能的重置函数中执行此操作,并且通常也直接在应用程序中看到(通常作为构造函数的参数 - 这通常是潜在的内存泄漏,但这是另一个问题的问题)。跨度> @mlvljr:先提出一个主观问题,然后再提出一个促进争论的主观问题。也许您错过了答案(现已删除),该答案在 4 cmets 的空间内被简化为人身攻击——这很有争议。 IMO,删除指针的函数应该有这样的名称:DeleteX、DestroyX、FreeX、ReleaseX。论点是否为 const 似乎至少没有进入图片。如果函数名没有这样说,我没有理由期望void FooBar(X*) 会承担所有权并释放对象。 - 至于智能指针:如果它只接受 const 指针,那么拥有一个指向可变对象的智能指针会不会很棘手? 【参考方案1】:

使用适当的策略来结束对象的生命周期是一种很好的做法。对于动态对象,这意味着删除新的内容,释放 malloc 的内容,等等。该对象是否为 const 对其生命周期是否结束没有影响。

常量或易失性是存在于对象生命周期内的属性,并且以删除表达式或对 free 的调用结束。无论您对此事的看法如何,或者事情在其他语言中是如何工作的,这就是 C++ 的对象模型的工作方式。一个简单的例子来说明这一点,该语言如何将删除表达式转换为运算符删除调用:

#include <new>
void* operator new(std::size_t size);
void operator delete(void* p);

int main() 
  delete new int(); // int* to void*, since this is also an allowed
  // implicit conversion, it may not be clear what is happening

  // however, these are clearly not implicit conversions:
  delete new int const();          // int const         * to void*
  delete new int volatile();       // int       volatile* to void*
  delete new int const volatile(); // int const volatile* to void*

另一个例子,但可能不太清楚,是为什么不能在 const 上重载 ctor:

struct S 
  S() const; // not allowed
;

一个对象只有在它被创建之后(也就是它的生命周期开始;在 ctor 正常返回时发生)和在它被销毁之前(也就是它的生命周期结束;在进入 dtor 时发生)才是 const。在该生命周期之前或之后,您可能有一个 T const* 类型的指针(例如),但它不指向对象并且取消引用它是 UB。

同样的推理也适用于 C,但您必须考虑到 C 有大约 40 年的历史,并且在大部分时间里成功地保持了大量的一致性。

(我认为这个问题是主观的和争论性的,并且会投票以这种方式结束它,除非我显然帮助了spark 讨论;所以以 CW 的身份回答。)

【讨论】:

【参考方案2】:

我从来没有真正理解反对删除(或释放)一个 const 指针的论点。更准确地说,我在某种程度上看到了理性,但在我看来,它们同样适用于对象中的 const 成员或 bloc 中的 const 变量,而且我从未见过有人争辩说这些不应该被破坏和他们的记忆当包含对象被删除或执行离开其包含块时释放。

管理对象的逻辑可变性(即是否为 const)和管理其生命周期(即使用对象变量、智能指针——其中一个——或原始指针)这两个问题似乎与我无关.

换句话说,如果


    Foo const x;
    ...

是有效且良好的风格。为什么会


    Foo const* xptr = new Foo;
    ...
    delete xptr;

风格不好(使用足够的智能指针而不是原始指针,但这是另一个问题)。

【讨论】:

@Poita_,恕我直言,所有权问题和逻辑可变性问题是独立的。我不明白为什么我应该仅仅因为我希望以后能够销毁该对象而将指向非 const 的指针保留为不可变对象。为了能够销毁对象,您必须是所有者,但这并不意味着您必须能够修改它。虽然让所有所有者实体无法修改对象而非所有者实体是有问题的,但拥有一个在销毁之前没有人能够修改的对象是有意义的,因为有两种所有者,一种能够修改,一个没有。 我同意,但我相信这是被问到的问题。 @Poita_:“这是所有权问题”,而不是恒定性问题。如果 foo 获得 xptr 的所有权,则 foo 负责释放它。【参考方案3】:

嗯,这里有一些相关的东西可能太长了,无法放入评论:

    前段时间,通过指向 const 的指针释放内存的做法是完全禁止的,请参阅 this dr. Dobb's article, the "Language Law" ( :)) part

    在http://groups.google.ru/group/comp.lang.c++.moderated 上有两次相关讨论:"Delete a const pointer?""Why can operator delete be called on a const pointer"(两者都实际处理有问题的情况,即指向 const 的指针)。

    我自己的观点(因为您要求参数):在任何给定上下文中所讨论的操作的可能性由类或函数的(在文档中显式或隐式定义)合同定义,而不是仅通过方法签名或参数类型。

【讨论】:

【参考方案4】:

常量和生命周期是两个不同的东西。如果 const 对象的所有者认为该对象没有理由存在,我认为释放该对象没有问题(同样的方式,本地的 const 对象在超出范围时将被“释放”)。

至于 free() 没有采用 const 指针,我认为有人可能会争辩说这可能是标准委员会的疏忽,或者那是因为它采用了与 malloc() 相同的指针返回。

【讨论】:

以上是关于通过指向常量的指针释放内存是一种好习惯吗的主要内容,如果未能解决你的问题,请参考以下文章

动态内存管理

指针free后还存在吗?

使用引用来布置简单的功能是一种好习惯吗

如何释放C中两个指针指向的内存? [复制]

glGenBuffers - 释放内存?

野指针