views:

310

answers:

4

There are many questions discussing the details of C and C++ dealing with pointer-to-const deletion, namely that free() does not accept them and that delete and delete[] do and that constness doesn't prevent object destruction.

What I am interested on is whether you think it is a good practice to do so, not what the languages (C and C++) allow.

Arguments for pointer-to-const deletion include:

  • Linus Torvalds' kfree(), unlike C's free(), takes a void const* argument because he thinks that freeing the memory does not affect what is pointed to.
  • free() was designed before the introduction of the const keyword.
  • C++'s delete operators allow deletion of const data.

Arguments against it include:

  • Programmers do not expect data to be modified (or deleted) when they pass a pointer-to-const to it.
  • Many think that pointer-to-const implies not getting ownership of the data (but not that non-const would imply getting ownership).
  • This is the common practice seen in most libraries and existing code.

Please argument well in your responses and possibly refer to authorities. My intention is not to start a poll here.

+3  A: 

I've never really understood the arguments against deleting (or freeing) a const pointer. More precisely, I somewhat see the rational but it seems to me that they apply equally well to a const member in an object or a const variable in a bloc, and I've never see anybody argue that those should not be destroyed and their memory freed when the containing object is deleted or the execution leaves their containing block.

The two issues of managing the logical mutability of objects (i.e. const or not) and managing their life length (i.e. use an object variable, a smart pointer -- which and one -- or a raw pointer) seems unrelated to me.

In other words, if

{
    Foo const x;
    ...
}

is valid and good style. Why would

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

not be good style (using an adequate smart pointer instead of a raw one, but that is another issue).

AProgrammer
He isn't arguing against the second style. It's an issue of ownership; that block of code there owns `xptr` so it is free to do what it wants with it. What he is arguing is that if somewhere in that block you called `foo(xptr)`, would it be good practice for `foo` to be allowed to `delete` `xptr`?
Peter Alexander
+1 for a good argument
Tronic
@Poita_, IMHO the ownership issue and the logical mutability issue are independent. I don't see why I should keep a pointer to non const an immutable object just because I want to be able to destroy the object later. To be able to destroy the object, you have to be an owner, but that doesn't imply that you have to be able to modify it. While it would be questionable to have the all owner entities not able to modify the object while a non owner entity is, having an object that nobody is able to modify until it is destroyed make sense as having two kinds of owners, one able to modify, one not.
AProgrammer
I agree, but I believe that was the question that was being asked.
Peter Alexander
@Poita_: "It's an issue of ownership," not an issue of constness. If foo takes ownership of xptr, then foo is responsible for deallocating it.
Roger Pate
+1  A: 

Well, here's some relevant stuff possibly too long to fit into a comment:

  1. Some time ago the practice to free memory via a pointer-to-const was plain forbidden, see this dr. Dobb's article, the "Language Law" ( :)) part.

  2. There has twice been a relevant discussion on http://groups.google.ru/group/comp.lang.c++.moderated: "Delete a const pointer?", "Why can operator delete be called on a const pointer" (both actually deal with the case in question, i.e. pointer to const).

  3. My own point (since you are asking for arguments): possibility of the operation in question in any given context is defined by the (explicitly or implicitly defined in the documentation) contract of a class or a function, not by just the method signature or parameter types.

mlvljr
The most complete answer with a lot of insight. It is strange that such a small issue could provoke so much flames.
Tronic
@Tronic You (probably) praise it too high, but thanks:))
mlvljr
+4  A: 

It is a good practice to use the proper strategy to end the lifetime of an object. For dynamic objects this means delete what you new, free what you malloc, and so forth. Whether that object is const or not has no affect on whether its lifetime should end.

Being constant or volatile are properties that exist within an object's lifetime, and that ends with a delete-expression or a call to free. Regardless of your own views on the matter or how things work in other languages, this is how C++'s object model works. A simple example to show this is how the language translates delete-expressions into operator delete calls:

#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*
}

Another example, but perhaps less clear, is why you cannot overload ctors on const:

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

An object is only const after it is created (aka its lifetime begins; happens when the ctor returns normally) and before it is destroyed (aka its lifetime ends; happens as the dtor is entered). Before or after that lifetime you may have a pointer of type T const* (for example), but it does not point to an object and dereferencing it is UB.

The same line of reasoning applies to C, except you have to consider that C has roughly 40 years of history and has succeeded in maintaining a large amount of consistency for much of that time.

(I believe this question is subjective and argumentative and would vote to close it that way, except I apparently helped spark the discussion; so answering as CW.)

Roger Pate
A: 

Constness and lifetime are two different things. I see no problem freeing a const object if the owner of that object decides the object has no reason to live (the same way a const object that's a local will get 'deallocated' when it goes out of scope).

As far as free() not taking a const pointer, I think that one could argue either that that might have been an oversight of the standards committee or that that's because it takes the same kind if pointer that malloc() returns.

Michael Burr