Question

started moving some libraries from msvc to mingw, and found really interesting behavior of msvc when one wants to delete an array of upcasted objects. Namely msvc does some dark magic (it seems to love doing that) and the bellow code executes just fine, however in mingw (4.7.2( crashes. I believe that mingw is performing correctly and its the msvc voodoo thats the issue for making a sleeper bug.

Code:

#include <iostream>

class foo{
    static int idgen;
protected:
    int id;
public:
    foo(){
        id = idgen++;
        std::cout << "Hello  ( foo - "<<id<<")"<<std::endl;
    }
    virtual ~foo(){
        std::cout << "Bye bye ( foo - "<<id<<")"<<std::endl;
    };
};

int foo::idgen = 0;


class bar: public foo{
    double some_data[20];
public:
    bar(){

    std::cout << "Hello  ( bar - "<<id<<")"<<std::endl;
}
    ~bar(){
        std::cout << "Bye bye ( bar - "<<id<<")"<<std::endl;
    }
};

int main()
{
    const unsigned int size = 2;
    foo** arr = new foo*[size];
    {
        bar* tmp = new bar[size];
        for(int i=0; i<size; i++)
        {
            arr[i] = &(tmp[i]); //take address of each object
        }
    }

    delete [] arr[0]; //take address of first object, pointer is same as tmp. This also crashes mingw
    delete [] arr;

}

Output from msvc 2010

Hello  ( foo - 0)
Hello  ( bar - 0)
Hello  ( foo - 1)
Hello  ( bar - 1)
Bye bye ( bar - 1)
Bye bye ( foo - 1)
Bye bye ( bar - 0)
Bye bye ( foo - 0)

And mingw (crashed at the destruction)

Hello  ( foo - 0)
Hello  ( bar - 0)
Hello  ( foo - 1)
Hello  ( bar - 1) 

My question is, what is the correct approach to fix this. The current hackfix that I came up with involved just trying to downcast to every possible class and invoking the delete operation on the downcasted pointer:

if(dynamic_cast<bar*>(arr[0]) != 0)
    delete [] dynamic_cast<bar*>(arr[0]); 

Is there a better approach, besides redesigning the library (it isn't mine)?

Was it helpful?

Solution

In the standard specifications, Section 5.3.5 paragraph 3, regarding the delete operator:

[...] In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

So indeed, you should not rely on the gentle behaviour of Visual C++ in this case, and try to provide the array delete operator a pointer of the correct type, which basically means dynamic casting in your situation.

You may avoid that problem by using a vector instance to store your upcasted objects allocated one by one.

OTHER TIPS

gcc 4.7.2 fails even with a simple example here -> ideone.com/z876QX#view_edit_box So we can't apparently make use of virtual destructors if it is an array.

const unsigned int size = 2;
foo* test = new bar[size];
delete[] test;

However, you get away if you use an array of pointers that will allow you to use delete instead of delete[].

http://ideone.com/NfbF3n#view_edit_box

const int size = 5;
foo *test[size];
for(int i = 0; i < size; ++i)
    test[i] = new bar;
for(int i = 0; i < size; ++i)
   delete test[i];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top