Search code examples
c++virtual-functionstype-erasure

Debugging crash in small object optimization for type erasure


I'm implementing a class that performs type erasure for small objects and have encountered a segmentation fault which I do not understand.

The following program:

#include <iostream>
#include <type_traits>

struct small_object
{
  public:
    template<class T>
    small_object(const T& value)
    {
      new(&storage_) concrete<T>(value);
    }

    ~small_object()
    {
      get_abstract().~abstract();
    }

    void print() const
    {
      // XXX crash here
      get_abstract().print();
    }

  private:
    struct abstract
    {
      virtual ~abstract(){}

      virtual void print() const = 0;
    };

    template<class T>
    struct concrete
    {
      concrete(const T& value) : value_(value) {}

      void print() const
      {
        std::cout << value_ << std::endl;
      }

      T value_;
    };

    abstract& get_abstract()
    {
      return *reinterpret_cast<abstract*>(&storage_);
    }

    const abstract& get_abstract() const
    {
      return *reinterpret_cast<const abstract*>(&storage_);
    }

    typename std::aligned_storage<4 * sizeof(void*)> storage_;
};

int main()
{
  small_object object(13);

  // XXX i expect this line to print '13' to the terminal but it crashes
  object.print();

  return 0;
}

Crashes at the lines indicated by XXX.

I believe the issue is that the virtual call to .print() is not being dynamically dispatched correctly, but I don't understand why.

Can anyone tell what am I missing?


Solution

  • You didn't derive concrete<T> from abstract, so no vtable is being created when you construct the object using placement new. Therefore, when you try to invoke the virtual function, it will fail; concrete<T> and abstract are actually completely unrelated types in this example.

    I would recommend using the override keyword if you're using C++11 or newer to allow the compiler to generate an error in cases like this.