Skip to content

Commit f8e5ca8

Browse files
committed
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.
1 parent 4ef61fe commit f8e5ca8

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

doc/derivation.html

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,28 @@ <h3>Log Archive</h3>
7070
<li><i>Note the</i> <code style="white-space: normal">log_archive</code> <i>between the</i> &lt;&gt;
7171
This is required so that base classes can downcast their <code style="white-space: normal">this</code> pointer
7272
to the most derived class. This is referred to as <b>C</b>uriously <b>R</b>ecurring
73-
<b>T</b>emplate <b>P</b>attern (<b>CRTP</b>) <a href="bibliography.html#11">[11]</a>.
73+
<b>T</b>emplate <b>P</b>attern (<b>CRTP</b>) <a href="bibliography.html#11">[11]</a>.
7474
It is used to implement static polymorphism.
75+
<li><i>The most derived class is responsible for calling</i> <code style="white-space: normal">init()</code>.
76+
The archive header (signature and version) is written by <code style="white-space: normal">init()</code>.
77+
Before Boost 1.73, the <b>CRTP</b> base called <code style="white-space: normal">init()</code> from its own
78+
constructor, but that downcast <code style="white-space: normal">this</code> to the most derived class
79+
while that class was still being constructed, which is undefined behavior. As of 1.73, the base
80+
classes no longer do this, so a derived archive that wants the standard header must call
81+
<code style="white-space: normal">init()</code> itself, in its own constructor body, after the base
82+
sub-objects have been constructed, honoring the <code style="white-space: normal">no_header</code> flag:
83+
<pre><code>
84+
log_archive(std::ostream &amp; os, unsigned int flags = 0) :
85+
xml_oarchive_impl&lt;log_archive&gt;(os, flags)
86+
{
87+
if(0 == (flags &amp; boost::archive::no_header))
88+
init();
89+
}
90+
</code></pre>
91+
The <code style="white-space: normal">log_archive</code> shown in this example passes
92+
<code style="white-space: normal">no_header</code>, so it has no header to write and its constructor
93+
body is empty; see <code style="white-space: normal">xml_oarchive</code>, or the
94+
<code style="white-space: normal">portable_binary_oarchive</code> example, for archives that do write one.
7595
<li><i>Base classes need to be explicitly given access to the derived class.</i>
7696
This can be done by making members public or by including friend declarations for
7797
the base classes.
@@ -135,7 +155,7 @@ <h3>Log Archive</h3>
135155
{
136156
public:
137157
log_archive(std::ostream &amp; os, unsigned int flags = 0) :
138-
log_archive_impl&lt;xml_oarchive&gt;(os, flags)
158+
log_archive_impl&lt;log_archive&gt;(os, flags)
139159
{}
140160
};
141161
</code></pre>

0 commit comments

Comments
 (0)