C++ tidbit #6: Virtual functions and trivial copy

C++ tidbit #6: Virtual functions and trivial copy

Trivial Copyability

In C++ terms an object is `trivially-copyable` if it is ok to memcpy it around. Containers (stl and custom) typically rely on `std::is_trivially_copyable<T>` to specialize copy operations of a bulk of T objects. Techincally, A copy ctor is considered trivial when:

  1. It is not user-provided,
  2. The underlying class has no virtual functions,
  3. <other conditions>

Condition (1) seems reasonable, but why condition (2)? What might go wrong when memcpy'ing an instance of a class with virtual functions?

Object Slicing

Let's focus on this toy snippet.


struct B {
    int b; 
    virtual void f(); 
};
struct D : B { 
    int d; 
    void f() override;
};        

Everything is fine if you memcpy real B's around, and everything is fine if you memcpy real D's.

But what about -


  D d;
  B& b = d;    // can we memcpy?        

This is essentially object slicing: assigning a derived object to a parent (and in the process, 'slicing' away the derived-only members). Our code is more referencing than assigning, but the essential problem remains if we try to memcpy:

No alt text provided for this image

The 1st element of the object's memory is a pointer to the class' vtable (a table of pointers to the virtual functions, shared among all class instances). A few things to note:

  1. When assigning to the reference-to-base `B& b = d` the vfptr remains unchanged, and so b.f() would invoke D::f, as desired.
  2. The d member is inaccessible via the B reference, but it is in place for use by D::f as needed.
  3. Any reasonable routine memcpy'ing a B object would memcpy only sizeof(B) bytes, thereby creating an object in an inconsistent state: calling f would invoked the derived D::f which could try to use the derived member D::b, but nothing meaningful is there.

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics