10

Possible Duplicate:
Is it safe to delete a void pointer?

Say I have a new allocation to a class called MyClass and allocation is as simple as:

MyClass *myClassPtr = new MyClass();

And I store reference to the list of void* where I simply say

myListOfPointers.add(static_cast<void*>(myClassPtr)); // this has to be void*

And later I release memory so instead of doing:

delete myClassPtr

I use:

delete MyListOfPointer.get(0)

(Say myClassPtr reference is at zero-index.) Also, please note that it has to be void* since this list can store different types of pointers so I wouldn't know the type of pointer that I am deleting:

So I can't do any thing like:

delete static_cast<MyClass*>(MyListOfPointer.get(0))

Is this way going to release the correct memory size? (sizeof(MyClass))?

Note:
I am not looking for any answer pointing to smart pointers.

Community
  • 1
  • 1
abumusamq
  • 780
  • 1
  • 10
  • 29
  • You'll also have potential issues with destructors not being called... Hope you're aware of that... – Macmade Oct 06 '12 at 17:06
  • Yup certainly I am aware of that but my main concern is with memory release size here in this case – abumusamq Oct 06 '12 at 17:11
  • 1
    This looks similar to http://stackoverflow.com/questions/941832/is-it-safe-to-delete-a-void-pointer (and the answer is that it's not safe to delete void pointers) – Scott Earle Oct 06 '12 at 17:15

4 Answers4

14

Deleting through a void* results in undefined behavior, so you are guaranteed nothing.

5.3.5 Delete [expr.delete]

1 The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.
[...]
The operand shall have a pointer to object type, or a class type having a single non-explicit conversion function (12.3.2) to a pointer to object type. The result has type void.78

78) This implies that an object cannot be deleted using a pointer of type void* because void is not an object type.

Emphasis mine.


So even though you said not to say it, the answer is to create some form of smart pointer. It would need to use type-erasure to hide the type externally (allowing the heterogeneous list), but internally keep track of the type it was given and how to delete it. Something much like boost::any.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 1
    except a whole lot of uncertainty =) – WhozCraig Oct 06 '12 at 17:17
  • Any way you think to store type info so that it can be retrieved later. Something whose structure will be like: myClassPtr - MyClass myText - String .... etc – abumusamq Oct 06 '12 at 17:26
  • This is not undefined behaviour, it's ill-formed. `void*` is not a pointer-to-object type and is also not a class type with conversion operator, as such failing the conditions. – Xeo Oct 06 '12 at 17:27
  • @Xeo: I think the consensus from elsewhere was that breaking a "shall" is undefined behavior, and it's ill-formed if the text includes ", otherwise the program is ill-formed." Either way, I don't object to that interpretation (that's what I would have expected it to be). – GManNickG Oct 06 '12 at 17:31
  • 1
    @mkhan3189: Depends. As I've added to the answer, `boost::any` heads in the right direction for pure and basic type erasure. Otherwise, sounds like your design needs changing. Can all your objects derive from a base class with a virtual destructor? Then just store `std::unique_ptr`'s to instances of derived classes. If not, type erasure is effectively that one level abstracted. – GManNickG Oct 06 '12 at 17:33
  • I've never realised that `delete` is an expression, I've only ever seen it by itself in a statement. So you can do `for (auto i = array; i < std::end(array); delete *i++);` :) Not that you'd ever want to of course, but still. – Seth Carnegie Oct 06 '12 at 17:35
  • @GManNickG, yes thats the way I am going for, to use common base class with virtual dest'r :) thanks – abumusamq Oct 06 '12 at 18:15
2

A void pointer has no type information. If MyClass has a destructor, it will not be called. The compiler needs to know what it is deleting so it can generate the appropriate code. If all of your pointers in the list are of the same type then you should be storing that type in the list, not as void. If the pointers are different types but derive from a common base type, then give that base type a virtual constructor and store pointers of that type instead.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I thought of this before (of having a common base class) but I think I have issues with my design and I believe having such design would be a great idea. This post is helpful so +1 :) – abumusamq Oct 06 '12 at 17:36
  • what are your thoughts on: If I have a common base class (wit virtual cont'r and dest'r) and delete that base class by typecasting `static_cast(myClassPointer)` will this delete the correct size? (obviously the dest'r issue will be resolved because it has virtual destructor) but I am concerned with memory size. – abumusamq Oct 06 '12 at 17:48
  • 1
    Surely you mean "virtual destructor". There is no such thing as a "virtual constructor". – jamesdlin Oct 06 '12 at 18:02
  • 2
    @mkhan3189: If you have a common base class with a virtual destructor, `delete` will work fine. That's the entire point of having a virtual destructor. (Furthermore, `static_cast` is unnecessary. Pointers to derived types are can be implicitly cast to pointers to the base class.) – jamesdlin Oct 06 '12 at 18:04
1

It is not necessary to use a smart pointer, it's just smart.

That being said, there are many other possibilities; the only thing to do is to store the type information along the actual object.

class Holder {
public:
    template <typename T>
    explicit Holder(T const volatile* t):
        _data(static_cast<void const volatile*>(t)),
        _delete(&Delete<T>)
    {}

    void apply() { _deleter(_data); }

private:
    typedef void (*Deleter)(void const volatile*);

    template <typename T>
    static void Delete(void const volatile* p) {
        delete static_cast<T const volatile*>(p);
    }

    void const volatile* _data;
    Deleter _deleter;
};

And now:

std::list<Holder> owningList;

owningList.push_back(Holder(somePointer));

for (Holder& h: owningList) { h.apply(); }
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • @Matthew, oh no sorry bro didn't mean to be rude but your example is not helpful at all since i clearly said my pointers will be of different types. I take my words back but didn't mean to be rude. Cheer up bro, – abumusamq Oct 06 '12 at 18:13
  • @mkhan3189: sorry for being sharp then. If you look attentively you will note that the constructor of the class is templated. So you *can* use it with different types, as long as you preserve the type information right up until the moment you build the `Holder` class. Test it out with object that print in their destructors, you'll be surprised. – Matthieu M. Oct 06 '12 at 18:39
  • @Mathieu Bro, I don't need to test it in order to be surprised, i was already surprised by just looking at it. I am not talking about the class being a template. I am talking about the types of object std::list is storing. It shouldn't bound to just `Holder` class, it should a `generic pointer holder` which is either void* or common base class of many derived classes. So, all good bro, your example is not bad but certainly not the smartest one. I still wonder why did you make it this complicated but thats your choice. Thanks a lot for your answer – abumusamq Oct 06 '12 at 19:03
  • @mkhan3189: This is effectively what I was talking about when I spoke of type erasure...just because something seems complicated to *you* doesn't mean it's overly complicated or not the smartest one. This is a pretty standard approach (though personally I'd make a few tweaks here or there). – GManNickG Oct 06 '12 at 19:47
  • @GManNickG. Thanks bro, you made me realize that sometimes its good to accept someone's great help. – abumusamq Oct 07 '12 at 03:19
  • @MatthieuM. Cheers for your answer bro. I got your point by further investigating type erasures and by reading http://www.cplusplus.com/articles/oz18T05o/ – abumusamq Oct 07 '12 at 03:19
  • 1
    @mkhan3189: Glad to see you finally got to it :) It does look a bit like magic, but when you realize that virtual methods are nothing more than function pointers invoked dynamically, you also realize you can perfectly get this "dynamic" behavior without inheritance. Throw templates into the mix to get both automatic type deduction *and* automatic function creation, and you've got yourself a magical mix :) – Matthieu M. Oct 07 '12 at 10:39
0

The correct answer to this question is of course 'no'

Edit: asked to provide more information, even though I already did in a comment to the question, the deletion of a void* is undefined, and this question is another way of asking this one: Is it safe to delete a void pointer? - see the answers in there for details.

Community
  • 1
  • 1
Scott Earle
  • 660
  • 9
  • 21