Search code examples
c++containers

Why does the creation of a vector storing base objects, but being initialized with derived objects fail with a deleted move constructor?


I am attempting to create a std::vector<SystemBase> class member that stores multiple systems that all derive from SystemBase. However this class has a reference and thus has no sensible default constructor:

class SystemBase {
public:
  SystemBase() = delete;
  explicit SystemBase(entt::registry &Registry) : Registry{Registry} {}
  virtual ~SystemBase() = default;

  SystemBase(const SystemBase &) = delete;
  SystemBase(SystemBase &&) = delete;
  auto operator=(const SystemBase &) -> SystemBase & = delete;
  auto operator=(SystemBase &&) -> SystemBase & = delete;

  virtual auto update(const sf::Time DeltaTime) const -> void;

protected:
  entt::registry &Registry;
};

A system that inherits looks as follows:

class LocalToWorldSystem final : public SystemBase {
public:
  explicit LocalToWorldSystem(entt::registry &Registry) : SystemBase{Registry} {};
  auto update(const sf::Time DeltaTime) const -> void override;
};

When trying to initialize a vector of systems I get an error:

std::vector<SystemBase> Systems{LocalToWorldSystem{Registry}};
//                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Error: Call to deleted constructor of 'const SystemBase'.

Why does this happen? My current workaround is to use a std::vector<std::unique_ptr<SystemBase>> but I'd like to know why this issue pops up in the first place.


Solution

  • In C++, variables and objects of type X are actually objects of type X. They are never objects of a derived type.

    Pointers to base can point at derived. Derived objects have a base class subobject in them. But a vector of foo contains actual foos.

    In many C++ derived languages, variables of object type are actually pointers (often called references) to said objects. This often leads to primitive types having value semantics, while object types have reference or pointer semantics.

    A vector of unique ptrs, meanwhile, can store pointers to base that point to derived.