0

Is there a way to call destructor on objects if they are polymorphic types created with placement new?

class AbstractBase{
public:
    ~virtual AbstractBase(){}
    virtual void doSomething()=0;
};

class Implementation:public virtual AbstractBase{
public:
    virtual void doSomething()override{
        std::cout<<"hello!"<<std::endl;
    }
};

int main(){
    char array[sizeof(Implementation)];
    Implementation * imp = new (&array[0]) Implementation();
    AbstractBase * base = imp; //downcast
    //then how can I call destructor of Implementation from
    //base? (I know I can't delete base, I just want to call its destructor)
    return 0;
}

I want to destruct "Implementation" only thanks to a pointer to its virtual base... Is that possible?

CoffeDeveloper
  • 7,961
  • 3
  • 35
  • 69
  • 6
    `base->~AbstractBase()`, or `imp->~Implementation()`. You pick. – Casey Jul 24 '13 at 22:29
  • 3
    This isn't even valid C++. And you can `delete base`, which will call derived virtual destructors. And are you sure you want to use virtual inheritance here? – Aesthete Jul 24 '13 at 22:31
  • Yes you are right! http://ideone.com/Dv4JpO Thanks! Aesthete the solution from Casey is enough:). – CoffeDeveloper Jul 24 '13 at 22:36
  • 3
    There's no guarantee that `array` is properly aligned to store an `Implementation` - use `std::aligned_storage::type` instead of `char[sizeof(Implementation)]`. – Casey Jul 24 '13 at 22:39
  • 1
    @Aesthete Calling `delete base` will invoke undefined behaviour: "In the first alternative (*delete object*), the value of the operand of `delete` may be a null pointer value, a pointer to a non-array object created by a previous *new-expression*, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined." [expr.delete]/2 – dyp Jul 24 '13 at 22:39
  • possible duplicate of [How to properly free the memory allocated by placement new?](http://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new) – podkova Jul 24 '13 at 22:41
  • there are slight differences :/. – CoffeDeveloper Jul 24 '13 at 22:46
  • @podkova If the fact that `AbstractBase` is a `virtual` base class doesn't change anything for this scenario, I agree. And AFAIK, `virtual` makes no difference here. – dyp Jul 24 '13 at 22:46

1 Answers1

3

Overkill answer: with unique_ptr and a custom deleter!

struct placement_delete {
  template <typename T>
  void operator () (T* ptr) const {
    ptr->~T();
  }
};

std::aligned_storage<sizeof(Implementation)>::type space;
std::unique_ptr<AbstractBase,placement_delete> base{new (&space) Implementation};

Live at Coliru.

Casey
  • 41,449
  • 7
  • 95
  • 125
  • I think you should provide the alignment as second argument to `aligned_storage`. It seems not to be required, though. – dyp Jul 24 '13 at 22:56
  • 1
    Example: `std::aligned_storage :: type` – dyp Jul 24 '13 at 23:00
  • lol! you read my mind I needed that exactly for using it with a unique_Ptr deleter Casey :p – CoffeDeveloper Jul 24 '13 at 23:05
  • @DyP The second parameter to aligned storage - the alignment - has a magic default of "the most stringent alignment requirement for any C++ object type whose size is no greater than [the first parameter]" (§20.9.7.6 Table 57). I.e., the same alignment that `malloc` and `::operator new` would use when allocating that size. – Casey Jul 25 '13 at 00:33
  • `malloc` uses 16. which is not enough for AVX types. thus `_aligned_malloc` exists for other alignment requirement.s – v.oddou Apr 10 '15 at 05:21