Skip to content

refactor: remove virtual destructor from BasicIO to restore CRTP zero-overhead #2397

Description

@LHT129

Background

BasicIO<IOTmpl> uses CRTP (Curiously Recurring Template Pattern) for static polymorphism. All *Impl methods are dispatched via static_cast<IOTmpl&>(*this) — there is no dynamic dispatch.

However, the destructor is declared as virtual ~BasicIO() = default; in src/io/basic_io.h:59. This is the only virtual function in the entire hierarchy.

Problem

The virtual destructor introduces an unnecessary vtable pointer (vptr, 8 bytes) into every IO object:

  • CRTP is designed for zero-overhead static polymorphism — the vptr defeats this promise
  • No IO object is ever deleted through a BasicIO<>* base pointer (there is no public virtual base class)
  • The vptr wastes 8 bytes per object and adds an unnecessary indirect jump

Proposed Fix

  1. Change virtual ~BasicIO() = default; to a protected non-virtual ~BasicIO() = default;

    • Removes the vptr, restoring zero overhead
    • protected access prevents external code from deleting through a base pointer (compile-time safety)
  2. Remove override from all 7 subclass destructors:

    • MemoryIO, BufferIO, MMapIO, AsyncIO, ReaderIO, MemoryBlockIO, NonContinuousIO

Expected Impact

  • -8 bytes per IO object (vptr elimination)
  • Eliminates unnecessary virtual dispatch overhead
  • Restores the CRTP zero-overhead design intent

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageNeeds kind and version triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions