The PImpl idiom and the C++26 std::indirect type

https://lobste.rs/rss Hits: 32
Summary

PImpl (which stands for Pointer to implementation) is a programming tehnicque to remove implementation details from a class by placing them in a separate class that is accessed through an opaque pointer. Its purpose is to separate interfaces and implementations and minimize compile-time dependencies. In this article, we’ll at how the PImpl idiom is typically implemented in C++ and how C++26 simplifies its implementation. Implementing with a raw pointer We can implement the Pimpl idiom using raw pointers and abiding to the Rule of Five. This is a guideline that says that when a class defines a special member function (for resource management) it should define all five of them (destructor, copy constructor, copy assignment operator, move constructor, move assignment operator). To demonstrate this, we will use a widget that represents a UI element that has a label and can be clicked and on each click a counter is incremented. Therefore, a widget would have a counter and a label but these are implementation details that are hidden behind an implementation class. This Widget class definition looks as follows: #pragma once #include <string> class Widget { public: Widget(const std::string& name); ~Widget(); Widget(const Widget& other); Widget& operator=(const Widget& other); Widget(Widget&& other) noexcept; Widget& operator=(Widget&& other) noexcept; void click(); int clickCount() const; std::string label() const; private: struct Impl; Impl* pimpl_; }; The Widget::Impl class is an incomplete type here. It’s forward declared and defined in the .cpp file. The Widget class keeps a pointer to an object of this type. #include "Widget.h" struct Widget::Impl { std::string name; int clicks = 0; explicit Impl(std::string n) : name(std::move(n)) {} }; Widget::Widget(const std::string& name) : pimpl_(new Impl(name)) { } Widget::~Widget() { delete pimpl_; } Widget::Widget(const Widget& other) : pimpl_(new Impl(*other.pimpl_)) { } Widget& Widget::operator=(const Widget& other) { if (th...

First seen: 2026-07-23 18:08

Last seen: 2026-07-24 20:31