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

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.

Related

Check for non-deallocated pointer

Assume a pointer object is being allocated on one point and it is being returned to different nested functions. At one point, I want to de-allocate this pointer after checking whether it is valid or already de-allocated by someone.
Is there any guarantee that any of these will work?
if(ptr != NULL)
delete ptr;
OR
if(ptr)
delete ptr;
This code does not work. It always gives Segmentation Fault
#include <iostream>
class A
{
public:
int x;
A(int a){ x=a;}
~A()
{
if(this || this != NULL)
delete this;
}
};
int main()
{
A *a = new A(3);
delete a;
a=NULL;
}
EDIT
Whenever we talk about pointers, people start asking, why not use Smart Pointers.
Just because smart pointers are there, everyone cannot use it.
We may be working on systems which use old style pointers. We cannot convert all of them to smart pointers, one fine day.
if(ptr != NULL) delete ptr;
OR
if(ptr) delete ptr;
The two are actually equivalent, and also the same as delete ptr;, because calling delete on a NULL pointer is guaranteed to work (as in, it does nothing).
And they are not guaranteed to work if ptr is a dangling pointer.
Meaning:
int* x = new int;
int* ptr = x;
//ptr and x point to the same location
delete x;
//x is deleted, but ptr still points to the same location
x = NULL;
//even if x is set to NULL, ptr is not changed
if (ptr) //this is true
delete ptr; //this invokes undefined behavior
In your specific code, you get the exception because you call delete this in the destructor, which in turn calls the destructor again. Since this is never NULL, you'll get a STACK OVERFLOW because the destructor will go uncontrollably recursive.
Do not call delete this in the destructor:
5.3.5, Delete: If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will
invoke the destructor (if any) for the object or the elements of the array being deleted.
Therefore, you will have infinite recursion inside the destructor.
Then:
if (p)
delete p;
the check for p being not null (if (x) in C++ means if x != 0) is superfluous. delete does that check already.
This would be valid:
class Foo {
public:
Foo () : p(0) {}
~Foo() { delete p; }
private:
int *p;
// Handcrafting copy assignment for classes that store
// pointers is seriously non-trivial, so forbid copying:
Foo (Foo const&) = delete;
Foo& operator= (Foo const &) = delete;
};
Do not assume any builtin type, like int, float or pointer to something, to be initialized automatically, therefore, do not assume them to be 0 when not explicitly initializing them (only global variables will be zero-initialized):
8.5 Initializers: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized
So: Always initialize builtin types!
My question is how should I avoid double delete of a pointer and prevent crash.
Destructors are ought to be entered and left exactly once. Not zero times, not two times, once.
And if you have multiple places that can reach the pointer, but are unsure about when you are allowed to delete, i.e. if you find yourself bookkeeping, use a more trivial algorithm, more trivial rules, or smart-pointers, like std::shared_ptr or std::unique_ptr:
class Foo {
public:
Foo (std::shared_ptr<int> tehInt) : tehInt_(tehInt) {}
private:
std::shared_ptr<int> tehInt_;
};
int main() {
std::shared_ptr<int> tehInt;
Foo foo (tehInt);
}
You cannot assume that the pointer will be set to NULL after someone has deleted it. This is certainly the case with embarcadero C++ Builder XE. It may get set to NULL afterwards but do not use the fact that it is not to allow your code to delete it again.
You ask: "At one point, I want to de-allocate this pointer after checking whether it is valid or already de-allocated by someone."
There is no portable way in C/C++ to check if a >naked pointer< is valid or not. That's it. End of story right there. You can't do it. Again: only if you use a naked, or C-style pointer. There are other kinds of pointers that don't have that issue, so why don't use them instead!
Now the question becomes: why the heck do you insist that you should use naked pointers? Don't use naked pointers, use std::shared_ptr and std::weak_ptr appropriately, and you won't even need to worry about deleting anything. It'll get deleted automatically when the last pointer goes out of scope. Below is an example.
The example code shows that there are two object instances allocated on the heap: an integer, and a Holder. As test() returns, the returned std::auto_ptr<Holder> is not used by the caller main(). Thus the pointer gets destructed, thus deleting the instance of the Holder class. As the instance is destructed, it destructs the pointer to the instance of the integer -- the second of the two pointers that point at that integer. Then myInt gets destructed as well, and thus the last pointer alive to the integer is destroyed, and the memory is freed. Automagically and without worries.
class Holder {
std::auto_ptr<int> data;
public:
Holder(const std::auto_ptr<int> & d) : data(d) {}
}
std::auto_ptr<Holder> test() {
std::auto_ptr<int> myInt = new int;
std::auto_ptr<Holder> myHolder = new Holder(myInt);
return myHolder;
}
int main(int, char**) {
test(); // notice we don't do any deallocations!
}
Simply don't use naked pointers in C++, there's no good reason for it. It only lets you shoot yourself in the foot. Multiple times. With abandon ;)
The rough guidelines for smart pointers go as follows:
std::auto_ptr -- use when the scope is the sole owner of an object, and the lifetime of the object ends when the scope dies. Thus, if auto_ptr is a class member, it must make sense that the pointed-to object gets deletes when the instance of the class gets destroyed. Same goes for using it as an automatic variable in a function. In all other cases, don't use it.
std::shared_ptr -- its use implies ownership, potentially shared among multiple pointers. The pointed-to object's lifetime ends when the last pointer to it gets destroyed. Makes managing lifetime of objects quite trivial, but beware of circular references. If Class1 owns an instance of Class2, and that very same instance of Class2 owns the former instance of Class1, then the pointers themselves won't ever delete the classes.
std::weak_ptr -- its use implies non-ownership. It cannot be used directly, but has to be converted back to a shared_ptr before use. A weak_ptr will not prevent an object from being destroyed, so it doesn't present circular reference issues. It is otherwise safe in that you can't use it if it's dangling. It will assert or present you with a null pointer, causing an immediate segfault. Using dangling pointers is way worse, because they often appear to work.
That's in fact the main benefit of weak_ptr: with a naked C-style pointer, you'll never know if someone has deleted the object or not. A weak_ptr knows when the last shared_ptr went out of scope, and it will prevent you from using the object. You can even ask it whether it's still valid: the expired() method returns true if the object was deleted.
You should never use delete this. For two reasons, the destructor is in the process of deleting the memory and is giving you the opportunity to tidy up (release OS resources, do a delete any pointers in the object that the object has created). Secondly, the object may be on the stack.

C++ Overload or monitor the dereference operator (on a pointer)

I was wondering if it is possible to add code (checks of the validity of the object pointed to actually) when a pointer is dereferenced.
I saw many subjects on overloading operator ->, but it seems the operator was called on an object, not a pointer. Maybe (probably) there is something I'm misunderstanding.
here's an example :
T* pObj = new T();
pObj->DoStuff(); // call check code (not in DoStuff)
delete pObj;
pObj->DoOtherStuff(); // call check code (not in DoOtherStuff)
the "check code" should be independent from the function (or members) called. My idea was to set a member as an int in the class, and give it a defined value at construction (and destruction), then check the value.
As you may have guess I try to check for invalid pointers used. I try to read the code but it's far too big and complex to not miss many potential errors.
Thanks for your answers and insights.
operator-> can only be overloaded as a member function of a class, not for a normal pointer.
In general there is no way to check that a (non-null) pointer actually points to a valid object. In your example delete pObj; does nothing to change the pointer; it just leaves it pointing to invalid memory, and there is no way to test for that. So, even if you could overload operator-> here, the best it could do is check that it wasn't null.
The usual approach is to use smart pointers, rather than normal pointers. A smart pointer is a class that wraps a plain pointer to an object, and has overloads of operator* and operator-> so that it looks and feels like a pointer. You won't delete the object directly, but through the pointer (when it goes out of scope, or explicitly by calling a reset() function), and the pointer can then set its plain pointer to null when that happens. In that way, the plain pointer will always be either valid, or null, so the overloaded operators can usefully check it before dereferencing.
Smart pointers (and RAII in general) bring other advantages too: automatic memory management, and exception safety. In your code, there will be a memory leak if DoStuff() throws an exception; pObj will go out of scope, and so there will be no way to access it to delete the object it points to. The memory will be lost and, if this keeps happening, you will eventually use all the system's memory and either crash or slow to a crawl. If it were a smart pointer, then the object would be deleted automatically as it went out of scope.
Commonly used smart pointers from the Standard Library and Boost are auto_ptr, scoped_ptr and shared_ptr, each with different behaviour when copying the pointer. C++0x will introduce unique_ptr to replace auto_ptr.
You should overload operators -> and *, in more or less the same way that auto_ptr works.
For example:
template<typename T>
class SafePtr {
public:
SafePtr(T*p) : ptr(p) {}
T &operator*()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return *ptr;
}
T * operator->()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return ptr;
}
bool preConditions()
{ return ( ptr != NULL ); }
private:
T* ptr;
};
This could be a very basic example. The -> operator would be overloaded in a similar way. All the logic you want to execute before dereferencing the pointer would be coded inside preConditions(). I think that you can get the idea from here, if not, you can ask further.
Hope this helps.
operator -> (or any other operators) can be overloaded only for class objects and not for pointers. For your case, you can think of using standard/cutom Smart Pointers (which are actually objects and not pointer, but they can be used as of they are pointers).
If can not use smart pointers, then make a practice of assigning NULL after delete/free. Or you can use your custom wrapper for delete such as:
template<typename T>
void Destroy (T *&p) // use this wrapper instead of 'delete'
{
delete p;
p = 0;
}
As Nick already pointed out, use std::auto_ptr or better (and if possible) boost::shared_ptr. It basically implements almost exactly what you want.
To answer the question directly: indeed, you can only overload operator-> for a class, so in that case you won't be able to apply it to a pointer of that class. In other words, it will apply to objects, not pointers.
class T {
T& operator->() { }
};
void f() {
T* pObj = new T();
pObj->DoStuff(); // Calls DoStuff, but... Oops! T::operator->() was not called!
(*pObj).DoStuff(); // Equivalent to the above
delete pObj;
(*pObj)->DoStuff(); // T::operator->() is called, but
// there is no improvement here: the pointer is dereferenced
// earlier and since it was deleted, this will "crash" the application
//pObj->->DoStuff(); // Syntactically incorrect, but semantically equivalent
//to the above
pObj->operator->()->DoStuff(); // Semantically equivalent to the above two,
//but avoids the double member access operator.
}

c++ must delete a references?

in the following code:
class x
{
private:
someRef& m_ref;
public:
x(someRef& someRef):m_ref(someRef)
{
}
do I need to do:
~x()
{
delete m_ref;
}
which by the way doesnt work without getting the pointer...
basically I'm asking: Do I need to call a destructor on a reference member?
No.
You only need to delete an object if you own it. If you were passed a reference, it means that someone else owns it, thus it's unnecessary and thankfully the language prevents it.
I don't think one actually strictly speaking ever deletes even pointers. What you delete are dynamically allocated objects (or arrays of objects) that the pointer is a handle for. If the object originates from a call to new and it is the responsibility of this class to clean up after this object, then you call delete.
It is technically possible that a reference might be referring to a dynamically allocated object:
int main()
{
//in principle a reference can also refer to a dynamically allocated object
x var(*new someRef);
}
//and if that is the intended usage:
x::~x()
{
delete &m_ref;
}
However, this would be incredibly bad style. By convention, the "owning" handle of a dynamically allocated object should not be a reference.
No. You can only delete pointers, not references, and even then you must only delete objects that you allocated using the new operator. And then you must be sure to delete them only once. Here is the case in which you would need to use delete in your destructor:
class x
{
private:
someObj* m_ptr;
public:
x():m_ptr(new someObj())
{
}
~x()
{
delete m_ptr;
}
But in general it's best to avoid even this and use smart pointers instead.
I want to clarify some misconceptions you seem to have that are beyond the intent of your question:
When a class's destructor is called all of it's members' destructors get called as well.
Calling delete is not the same as calling the destructor. delete explicitly calls the destructor and also calls operator delete at the objects location, it is a 2 part thing.
For a small bit of extra clarification I want to offer the following:
int *pi = new int;
//int& ir = pi; // can't do
// this a reference to the pointer but it is an error
// because or the type difference int& vs int* and
// static_cast won't help. reinterpret_cast would allow
// the assignment to take place but not help the 'delete ir'
int& ir = *pi; // this is OK - a reference to what the pointer points to.
// In other words, the the address of the int on the heap.
//delete ir; // can't do, it is a reference and you can't delete non-pointers.
delete &ir; // this works but it is still not "deleting a reference".
// The reference 'ir' is another name for the heap-based int.
// So, &ir is the address of that int, essentially a pointer.
// It is a pointer that is being used by delete, not a reference.

How does delete deal with pointer constness?

I was reading this question Deleting a const pointer and wanted to know more about delete behavior. Now, as per my understanding:
delete expression works in two steps:
invoke destructor
then releases the memory (often with a call to free()) by calling operator delete.
operator delete accepts a void*. As part of a test program I overloaded operator delete and found that operator delete doesn't accept const pointer.
Since operator delete does not accept const pointer and delete internally calls operator delete, how does Deleting a const pointer work ?
Does delete uses const_cast internally?
const_cast doesn't really do anything – it's a way to suppress compiler moaning about const-ness of the object. delete keyword is a compiler construct, the compiler knows what to do in this case and doesn't care about const-ness of the pointer.
As this answer says, delete is not a method like any other, but a part of the langage to destruct objects. const-ness has no bearing on destructability.
operator delete accepts a void*. As part of a test program I overloaded operator delete and found that operator delete doesn't accept const pointer.
How did you try this? It certainly does accept const pointers:
#include <memory>
int main() {
void* const px = 0;
delete px;
::operator delete(px);
}
This code is correct, compiles (albeit with a justified warning) and executes.
EDIT: Reading the original article – you aren't talking about a const pointer but a pointer to const, which is something else. The reason why this has to work is described there. As for why it's working: others have said this.
delete is an operator that you can overload. It takes a pointer as an argument, and frees the memory, possibly using free. The compiler allows this whether the pointer is const or not.
delete just makes a call to deallocate the memory the pointer points to, it doesn't change the value of the pointer nor the object. Therefore, delete has nothing to do with the const-ness of the pointer or object pointed to.

Deleting a pointer to const (T const*)

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.