Deleting a pointer to const (T const*) - c++

I have a basic question regarding the const pointers. I am not allowed to call any non-const member functions using a const pointer. However, I am allowed to do this on a const pointer:
delete p;
This will call the destructor of the class which in essence is a non-const 'method'. Why is this allowed? Is it just to support this:
delete this;
Or is there some other reason?

It's to support:
// dynamically create object that cannot be changed
const Foo * f = new Foo;
// use const member functions here
// delete it
delete f;
But note that the problem is not limited to dynamically created objects:
{
const Foo f;
// use it
} // destructor called here
If destructors could not be called on const objects we could not use const objects at all.

Put it this way - if it weren't allowed there would be no way to delete const objects without using const_cast.
Semantically, const is an indication that an object should be immutable. That does not imply, however, that the object should not be deleted.

Constructors and Destructors should not be viewed as 'methods'. They are special constructs to initialise and tear down an object of a class.
'const pointer' is to indicate that the state of the object would not be changed when operations are performed on it while it is alive.

I am not allowed to call any non-const member functions using a const pointer.
Yes you are.
class Foo
{
public:
void aNonConstMemberFunction();
};
Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal
const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal
You have confused a const pointer to a non-const object, with a non-const pointer to a const object.
Having said that,
delete aConstPointer; // legal
delete aPointerToConst; // legal
it's legal to delete either, for the reasons already stated by the other answers here.

Another way to look at it: the precise meaning of a const pointer is that you will not be able to make changes to the pointed-to object that would be visible via that or any other pointer or reference to the same object. But when an object destructs, all other pointers to the address previously occupied by the now-deleted object are no longer pointers to that object. They store the same address, but that address is no longer the address of any object (in fact it may soon be reused as the address of a different object).
This distinction would be more obvious if pointers in C++ behaved like weak references, i.e. as soon as the object is destroyed, all extant pointers to it would immediately be set to 0. (That's the kind of thing considered to be too costly at runtime to impose on all C++ programs, and in fact it is impossible to make it entirely reliable.)
UPDATE: Reading this back nine years later, it's lawyer-ish. I now find your original reaction understandable. To disallow mutation but allow destruction is clearly problematic. The implied contract of const pointers/references is that their existence will act as a block on destruction of the target object, a.k.a. automatic garbage collection.
The usual solution to this is to use almost any other language instead.

Related

Return by reference in C++ - Reference assignment vs value assignment

Suppose I have:
class SomeObject {
};
SomeObject& f() {
SomeObject *s = new SomeObject();
return *s;
}
// Variant 1
int main() {
SomeObject& s = f();
// Do something with s
}
// Variant 2
int main() {
SomeObject s = f();
// Do something with s
}
Is there any difference between the first variant and the second? any cases I would use one over the other?
Edit: One more question, what does s contain in both cases?
First, you never want to return a reference to an object which
was dynamically allocated in the function. This is a memory
leak waiting to happen.
Beyond that, it depends on the semantics of the object, and what
you are doing. Using the reference (variant 1) allows
modification of the object it refers to, so that some other
function will see the modified value. Declaring a value
(variant 2) means that you have your own local copy, and any
modifications, etc. will be to it, and not to the object
referred to in the function return.
Typically, if a function returns a reference to a non-const,
it's because it expects the value to be modified; a typical
example would be something like std::vector<>::operator[],
where an expression like:
v[i] = 42;
is expected to modify the element in the vector. If this is
not the case, then the function should return a value, not
a reference (and you should almost never use such a function to
initialize a local reference). And of course, this only makes
sense if you return a reference to something that is accessible
elsewhere; either a global variable or (far more likely) data
owned by the class of which the function is a member.
In the first variant you attach a reference directly to a dynamically allocated object. This is a rather unorthodox way to own dynamic memory (a pointer would be better suited for that purpose), but still it gives you the opportunity to properly deallocate that object. I.e. at the end of your first main you can do
delete &s;
In the second variant you lose the reference, i.e. you lose the only link to that dynamically allocated object. The object becomes a memory leak.
Again, owning a dynamically allocated object through a reference does not strike me as a good practice. It is usually better to use a pointer or a smart pointer for that purpose. For that reason, both of your variants are flawed, even though the first one is formally redeemable.
Variant 1 will copy the address of the object and will be fast
Variant 2 will copy the whole object and will be slow (as already pointed out in Variant2 you cant delete the object which you created by calling new)
for the edit: Both f contain the same Object
None of the two options you asked about is very good. In this particular case you should use shared_ptr or unique_ptr, or auto_ptr if you use older C++ compilers, and change the function so it returns pointer, not reference. Another good option is returning the object by value, especially if the object is small and cheap to construct.
Modification to return the object by value:
SomeObject f() { return SomeObject(); }
SomeObject s(f());
Simple, clean, safe - no memory leaking here.
Using unique_ptr:
SomeObject* f() { return new SomeObject(); }
unique_ptr<SomeObject> s(f());
One of the advantages of using a unique_ptr or shared_ptr here is that you can change your function f at some point to return objects of a class derived from SomeObject and none of your client code will need to be changed - just make sure the base class (SomeObject) has a virtual constructor.
Why the options you were considering are not very good:
Variant 1:
SomeObject& s = f();
How are you going to destroy the object? You will need address of the object to call it's destructor anyway, so at some point you would need to dereference the object that s refers to (&s)
Variant 2. You have a leak here and not a chance to call destructor of the object returned from your function.

Local object pointer

struct Temp
{
CString one;
CString two;
};
class Foo
{
public:
Temp obj;
void somewhere();
}
void Foo::somewhere()
{
void* pData = static_cast<void*>(&obj);
OwnMethod(pData); // void OwnMethod(void*);
}
The question is:
Should I create obj on heap or this situation isn't dangerous (passing local class objects pointer)?
If OwnMethod(pData) stores the pointer somwhere for later use, that later use is not possible anymore, once the object on which Foo::somewhere() is called is destroyed.
If OwnMethod(pData) only access the pointed to data, you are safe.
The member variable will last as long as the Foo object, so the pointer will be valid during the call to OwnMethod.
If that function stores a copy of the pointer somewhere, and something else uses that pointer later, then there is a danger that it might be accessed after the Foo (and therefore the pointer's target) have been destroyed. There are various ways to prevent that; as you say, one is to dynamically allocate the object, and then transfer or share ownership when it's passed to OwnMethod. Smart pointers, such as std::unique_ptr and std::shared_ptr, are a very good way to track ownership of dynamic objects.
Wow, a lot of issues.
A complex object should't be passed to anything taking a void*.
Who wrote OwnMethod?
Why doesn't it take a pointer of type Foo*?
In fact why doesn't it take a reference of type Foo&?
If OwnMethod() may be required to accept objects of several different types then it should take a base class pointer or reference and use polymorphism.
However as far as the lifetime arguments go - obj will exist as long as the wrapping class does, so if the pointer is not used beyond the scope of OwnMethod this is ok. If OwnMethod causes the pointer to be stored elsewhere beyond Foo's lifetime then you have an issue, and maybe obj should be allocated on the heap. (And it might not even be appropriate for it to be a member of Foo at all.)

C++: Reference to dynamic memory

All considerations about when to use which aside, I am still unsure about pointer vs reference semantics.
Right now, I am under the impression that references are essentially pointers that must be initialized when they are declared, and then from that point on cannot point to anything else. In other words, they are a like a Type* const (not Type const*), or, they cannot be reseated. It essentially becomes a "new name" for that object. Now I heard that references do not actually need to be implemented by the compiler using pointers, but I am under the impression that you can still think of them this way, in regards to what their visible behavior will be.
But why can't you do something like this:
int& foo = new int;
I want to create a reference to dynamic memory. This does not compile. I get the error
error: invalid initialization of non-const reference of type 'int&' from a temporary of type 'int*'
That makes sense to me. It seems the new operator returns a pointer of given type to the address of memory that the OS? dynamically allocated for me.
So how do I create a "reference" to dynamic memory?
Edit: Links to resources that precisely explain the difference between references and pointers in C++ would be appreciated.
new returns a pointer to the allocated memory, So you need to capture the return value in a pointer.
You can create a reference to a pointer after allocation is done.
int *ptr = new int;
int* &ref = ptr;
then delete it after use as:
delete ref;
or more simply,
int &ref = *(new int);
delete it after use as:
delete &ref;
References are syntactic sugar. They allow one to access an object with the dot operator rather than the arrow.
Your choice of whether to use a pointer or a reference is semantic. When you pass an object by reference to a method, or return a reference from a method, you are saying: "This is my object and you may use it, but I own it (and it may be on the stack or the heap.)" It follows that the other answers here which suggest syntax like delete &foo; might technically work, but smell bad; If you have a reference to an object then you shouldn't be deleting it. You don't own it and, most importantly, as you can't reset the reference you end up with a reference to deallocated memory, which is a bad thing.
Now, if you have allocated an object on the heap (called 'new' to create it) then you do own it, and are responsible for cleaning it up later, so you need to hold a pointer to it. Why? So you can safely delete it later and null-out the pointer.
It follows that the difference between a pointer and a reference, other than the mechanical difference of using dot rather than arrow, is that by passing by reference to a method you indicate something about how an object should be used. To initialise a reference directly by calling new is nonsense, even if possible.
You can get a reference like this:
int& foo = *(new int);
In general, to get from T* to T& you use * to "dereference" the pointer.
However this is not a very good idea in the first place. You usually use pointers to store addresses of heap-allocated objects.

How can this compile? (delete a member of const object)

I would expect an error inside the copy constructor, but this compiles just fine with MSVC10.
class Test
{
public:
Test()
{
p = new int(0);
}
Test(const Test& t)
{
delete t.p; // I would expect an error here
}
~Test()
{
delete p;
}
private:
int* p;
};
This is a common issue with pointers. There is no way of actually disabling code from calling delete on a pointer (other than controlling access to the destructors). The first thing that you can hear is that the delete does not modify the pointer, but rather the pointed object. This can easily be checked by printing the pointer (std::cout << static_cast<void*>(p);) before and after a delete, so even if the pointer is constant the operation is not modifying it.
A little less intuitive is the fact that you can delete a pointer to a constant element --and the delete surely modifies the pointed element. But the language needed to be able to destruct constant objects when they fell out of scope (think { const mytype var(args); }) so const-ness cannot really affect the ability to destroy an object, and if that is allowed for auto variables, it does not make much sense to change the behavior for dynamically allocated objects. So at the end this is also allowed.
The issue that you are running into here is that you are not changing p per se (thus pstays immutable as you're not changing its value), but you're changing what p points to and thus are working at one additional level of indirection. This is possible because deleteing the memory associated with a pointer doesn't change the pointer itself.
In a strict sense the const-ness of the object is preserved, even though its logical constness has been violated as you pulled the rug from underneath whatever p was pointing to.
As JonH mentioned in the comment, if you were not able to delete the object pointed to by a pointer held in a const object, you would end up with memory leaks because you wouldn't be able to clean up properly after the object.
Constants are immutable, but that doesn't guarantee that they cannot be deleted. How would you ever delete an object if delete wasn't allowed.
If you try to modify t.p that should throw an error as t is const. But deleting t is quite normal even if it is constant.
Having:
int* const p;
... does not disallow operator delete from being called on p. Having const int* also does not disallow operator delete from being called on it.
Typical operator delete implementations take void* and any pointer will be implicitly cast to it (actually this might be the standard behavior to take void* or the only reasonable way to implement one global operator delete which can delete anything). Also as an interesting tidbit, one can implement their own overloaded operator delete (either globally or per-class) which takes void* and only has to free the memory allocated by new. The destructor call is implicitly added before any call to operator delete by the compiler; operator delete does not call the dtor in its implementation.
It is also worth noting that having const Test& in this case basically modifies the member, int* p so that it's analogous to int* const p, not int const* p or const int* p.
Thus:
Test::Test(const Test& other)
{
*other.p = 123; // this is valid
other.p = NULL; // this is not valid
}
In other words, the pointer address is immutable, but the pointee is not. I've often encountered a lot of confusion here with respect to member function constness and the effect it has on data members which are pointers. Understanding this will give a little insight as to one of the reasons why we need the separation between iterator and const_iterator.

Is it a good practice to free memory via a pointer-to-const

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.
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.)
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).
Well, here's some relevant stuff possibly too long to fit into a comment:
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.
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).
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.
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.