template<
class T, std::size_t Size, std::size_t Alignment,
bool Strict = false>
class utils::FastPimpl< T, Size, Alignment, Strict >
Implements pimpl idiom without dynamic memory allocation.
FastPimpl doesn't require either memory allocation or indirect memory access. But you have to manually set object size when you instantiate FastPimpl.
Example usage:
Take your class with pimpl via smart pointer and replace the smart pointer with utils::FastPimpl<Impl, Size, Alignment>
#pragma once
namespace sample {
class Widget {
public:
Widget();
Widget(Widget&& other) noexcept;
Widget(const Widget& other);
Widget& operator=(Widget&& other) noexcept;
Widget& operator=(const Widget& other);
~Widget();
int DoSomething(short param);
private:
struct Impl;
static constexpr std::size_t kImplSize =
static constexpr std::size_t kImplAlign = alignof(void*);
};
}
If the Size and Alignment are unknown - just put a random ones and the compiler would show the right ones in the error message:
[with int ActualSize = 1; int ActualAlignment = 8; T = sample::Widget;
int Size = 8; int Alignment = 8]'
Change the initialization in source file to not allocate for pimpl
#include "widget_fast_pimpl_test.hpp"
#include "third_party_ugly.hpp"
namespace sample {
struct Widget::Impl {
int Do(short param) const;
Ugly payload_;
};
Widget::Widget() : pimpl_(Impl{}) {}
Widget::Widget(Widget&& other) noexcept = default;
Widget::Widget(const Widget& other) = default;
Widget& Widget::operator=(Widget&& other) noexcept = default;
Widget& Widget::operator=(const Widget& other) = default;
Widget::~Widget() = default;
int Widget::DoSomething(short param) { return pimpl_->Do(param); }
}
Done! Now you can use the header without exposing the implementation details:
#include "widget_fast_pimpl_test.hpp"
#include <gtest/gtest.h>
TEST(FastPimpl, SampleWidget) {
sample::Widget widget;
auto widget_copy = widget;
EXPECT_EQ(widget_copy.DoSomething(2), 42);
}
Definition at line 46 of file fast_pimpl.hpp.