-1

As a Master Thesis I need to expand the database duckdb on github with functionality.

One of the first steps was to create a fixed internal plan that represents something like "select 42;" just on physical level. To that end I tired to manually create such a plan with the classes used internally by duckdb.

On compiling I generally get an error message like this:

/home/ubuntu/git/duckdb/src/include/common/helper.hpp: In instantiation of ‘std::unique_ptr<T> duckdb::make_unique(Args&& ...)

 [with T = duckdb::Expression; Args = {duckdb::ExpressionType,
 duckdb::ExpressionClass, duckdb::TypeId}]’:   

 /home/ubuntu/git/duckdb/src/execution/physical_plan_generator.cpp:125:155:
 required from here   

 /home/ubuntu/git/duckdb/src/include/common/helper.hpp:24:23: error:

 invalid new-expression of abstract class type ‘duckdb::Expression’   
 return unique_ptr<T>(new T(std::forward<Args>(args)...));

The creation was this line:

unique_ptr<Expression> ProjectionExpression = make_unique<Expression>(ExpressionType::VALUE_CONSTANT, ExpressionClass::BOUND_CONSTANT, TypeId::INTEGER);

The constructor is

Expression::Expression(ExpressionType type, ExpressionClass expression_class, TypeId return_type)
    : BaseExpression(type, expression_class), return_type(return_type) {
}

with baseexpression being

   BaseExpression(ExpressionType type, ExpressionClass expression_class)
        : type(type), expression_class(expression_class) {
    }
    virtual ~BaseExpression() {
    }

As you can see the class expression uses an initialization list from class baseExpression. As Far as I can tell there is no direct inheritance between the 2 but clearly I need something that is currently missing to correctly initialize the constructor.

The problem is that normally in duckdb these things come from the parser and get then built from these objects. And I have to try and guess how the data structure is supposed to look like.

I am having problems figuring out how to directly allocate this object with make_unique because expression clearly requires a baseExpression of somekind but baseexpression itself has a virtual component so I can't just create that one directly either.

basically what I am asking is: How do you make a new unique_ptr object when the class is abstract?

Hannes Mühleisen
  • 2,542
  • 11
  • 13
Student01
  • 93
  • 7
  • 2
    You have to instantiate some derived class, not an abstract class. Whether with `unique_ptr`, or with any other method of construction, you cannot instantiate abstract classes in C++. C++ does not work this way. – Sam Varshavchik Oct 28 '19 at 10:56

2 Answers2

0

How do you make a new unique_ptr object when the class is abstract?

By creating an instance of a concrete non-abstract subclass, and returning that as a pointer the to abstract base class. This is common practice when using the Factory pattern and similar idioms.

Useless
  • 64,155
  • 6
  • 88
  • 132
-1

Looking into the source code at here, you see that Expression has a pure virtual member function (recognizable by virtual and the = 0):

class Expression : public BaseExpression {
    //...

    virtual unique_ptr<Expression> Copy() = 0;

    //...
 };

A class with a pure virtual member function is an abstract class. Instances of abstract classes can not be created (whether as variables with automatic storage duration, with new or with std::make_unique). Instead you need to choose the appropriate class derived from Expression that implements all pure virtual methods and create an instance of that class, e.g. by calling std::make_unique<DerivedClass>(...). You can still assign that to std::unique_ptr<Expression> afterwards.

The problem is not virtual member functions in general, only pure virtual member functions. Without pure virtual member functions, classes with virtual functions can be used with std::make_unique without problem.

walnut
  • 21,629
  • 4
  • 23
  • 59