From bb67164668feb254659a10df5541f77d43661134 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 22 Jul 2026 10:36:49 +0200 Subject: [PATCH] Document that a derived archive must call init() itself Since Boost 1.73, the CRTP base archive classes no longer call `init()` from their constructors: doing so downcast this to the most derived class while it was still being constructed, which is undefined behavior and tripped the sanitizers. The derivation guide still showed the old pattern, in which a class derived from one of the `xxx_oarchive_impl` templates relied on the base to write the archive header. Following it now yields an archive that never writes its header. The guide now states that the most derived class is responsible for calling `init()` in its own constructor body, honoring `no_header`, and shows how, noting that the log_archive example is empty only because it suppresses the header. This also corrects the curiously recurring template argument in the further-derivation sketch, which named `xml_oarchive` instead of `log_archive`. Refs issue #182. --- doc/derivation.html | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/derivation.html b/doc/derivation.html index 843b88b31..6c7279264 100644 --- a/doc/derivation.html +++ b/doc/derivation.html @@ -70,8 +70,28 @@

Log Archive

  • Note the log_archive between the <> This is required so that base classes can downcast their this pointer to the most derived class. This is referred to as Curiously Recurring -Template Pattern (CRTP) [11]. +Template Pattern (CRTP) [11]. It is used to implement static polymorphism. +
  • The most derived class is responsible for calling init(). +The archive header (signature and version) is written by init(). +Before Boost 1.73, the CRTP base called init() from its own +constructor, but that downcast this to the most derived class +while that class was still being constructed, which is undefined behavior. As of 1.73, the base +classes no longer do this, so a derived archive that wants the standard header must call +init() itself, in its own constructor body, after the base +sub-objects have been constructed, honoring the no_header flag: +
    
    +    log_archive(std::ostream & os, unsigned int flags = 0) :
    +        xml_oarchive_impl<log_archive>(os, flags)
    +    {
    +        if(0 == (flags & boost::archive::no_header))
    +            init();
    +    }
    +
    +The log_archive shown in this example passes +no_header, so it has no header to write and its constructor +body is empty; see xml_oarchive, or the +portable_binary_oarchive example, for archives that do write one.
  • Base classes need to be explicitly given access to the derived class. This can be done by making members public or by including friend declarations for the base classes. @@ -135,7 +155,7 @@

    Log Archive

    { public: log_archive(std::ostream & os, unsigned int flags = 0) : - log_archive_impl<xml_oarchive>(os, flags) + log_archive_impl<log_archive>(os, flags) {} };