Simplest C++ Callback, from SumatraPDF
SumatraPDF as a PDF Reader
- Many comments praise SumatraPDF as fast, tiny, and “just works,” especially compared to Acrobat and browser viewers.
- Common use cases: LaTeX workflows (auto-reload on file changes, sync with editors), large/complex engineering PDFs, ebooks (epub, cbz/cbr), and keeping PDFs separate from the browser.
- Several argue browsers are too slow and memory-hungry for big or many PDFs; others say they rarely need more than the browser viewer.
- Some mention security: concern over lack of sandboxing vs. others noting Sumatra disables JavaScript and sanitizes text via HarfBuzz.
Why a Custom Callback Type
- The article presents
Func0/Func1<T>(function pointer +void* userData) instead ofstd::function. - Claimed benefits:
- Better crash stack traces than lambdas wrapped in
std::function(no anonymous compiler-generated types). - Smaller objects, simpler implementation, faster runtime and compile times, and code the author fully understands.
- Better crash stack traces than lambdas wrapped in
- The author explicitly avoids “fancy” modern C++ features and says they don’t understand most of C++ and prefer minimal constructs.
std::function, Lambdas, and Alternatives
- Many argue this is an inferior reimplementation of
std::function/std::function_ref/function2, which already cover this use case with type erasure and small-buffer optimization. - Others propose simpler alternatives:
- Virtual interfaces (one-method classes), possibly via a templated base.
std::functionwith lambdas that just forward to named member functions to keep stack traces usable.std::bindorstd::bind_frontfor binding receivers.
- Some note the custom design lacks perfect forwarding, can’t easily handle non-copyable types, and always heap-allocates captured data.
Performance, “NIH,” and Engineering Trade-offs
- Critics call this “NIH” and question unbenchmarked claims of speed/size gains. They invoke Amdahl’s law and ask for numbers.
- Supporters counter that in a one-person, performance-focused project, small bespoke utilities can be justified, and many such micro-choices can add up.
- There’s disagreement on whether
std::function’s overhead is meaningful in a GUI app.
Correctness and Portability Concerns
- Multiple commenters flag:
- Casting between function pointers and
void*and using-1as a sentinel pointer as undefined or at least implementation-defined on some platforms. - Potential trouble with control-flow integrity if function pointers are called with mismatched types.
- Casting between function pointers and
- Alternatives suggested: wrappers that keep types consistent, or using
intptr_t/uintptr_tfor sentinels instead of invalid pointer values.
C++ Complexity and Attitudes
- The author’s remark about not knowing “80% of C++” resonates with many; experienced developers admit similar and focus on a small, stable subset.
- Some argue you should rely on contracts, not internal implementations; others say in C++ with remote crash logs, understanding library internals and toolchain behavior is often necessary.