Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions include/cereal/archives/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,36 @@ namespace cereal
itsNodeStack.push(NodeType::StartObject);
}

//! Destructor, flushes the JSON
~JSONOutputArchive() CEREAL_NOEXCEPT
//! Explicitly finishes the JSON output and flushes to the stream
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By allowing this to be called outside of the destructor it does open up a case where the user calls close() then attempts to use the archive again. Have you tested what happens when this occurs? At minimum the description should mention that the archive will enter into undefined territory after calling this and further using the archive. I don't really want to put an overhead of checking against itsClosed to save the user in this case, as this is probably an off-nominal use case.

/*! This method can be used to detect and handle errors that occur during
finalization of the JSON output, similar to std::fstream::close().
If not called explicitly, the destructor will attempt the same
finalization but will silently swallow any exceptions.

It is safe to call close() multiple times; subsequent calls are no-ops.

@throws RapidJSONException if rapidjson encounters an error during finalization */
void close()
{
if( itsClosed )
return;
itsClosed = true;

if (itsNodeStack.top() == NodeType::InObject)
itsWriter.EndObject();
else if (itsNodeStack.top() == NodeType::InArray)
itsWriter.EndArray();
}

//! Destructor, flushes the JSON
/*! Silently catches any exceptions to guarantee noexcept.
Call close() explicitly before destruction to detect errors. */
~JSONOutputArchive() CEREAL_NOEXCEPT
{
try { close(); }
catch(...) {}
}

//! Saves some binary data, encoded as a base64 string, with an optional name
/*! This will create a new node, optionally named, and insert a value that consists of
the data encoded as a base64 string */
Expand Down Expand Up @@ -385,6 +406,7 @@ namespace cereal
char const * itsNextName; //!< The next name
std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
std::stack<NodeType> itsNodeStack;
bool itsClosed = false; //!< Whether close() has been called
}; // JSONOutputArchive

// ######################################################################
Expand Down
27 changes: 25 additions & 2 deletions include/cereal/archives/xml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,36 @@ namespace cereal
itsOS.precision( options.itsPrecision );
}

//! Destructor, flushes the XML
~XMLOutputArchive() CEREAL_NOEXCEPT
//! Explicitly finishes the XML output and flushes to the stream
/*! This method can be used to detect and handle errors that occur during
finalization of the XML output (e.g., stream I/O failures), similar
to std::fstream::close().
If not called explicitly, the destructor will attempt the same
finalization but will silently swallow any exceptions.

It is safe to call close() multiple times; subsequent calls are no-ops.

@throws std::exception if the stream operations fail */
void close()
{
if( itsClosed )
return;
itsClosed = true;

const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
rapidxml::print( itsStream, itsXML, flags );
itsXML.clear();
}

//! Destructor, flushes the XML
/*! Silently catches any exceptions to guarantee noexcept.
Call close() explicitly before destruction to detect errors. */
~XMLOutputArchive() CEREAL_NOEXCEPT
{
try { close(); }
catch(...) {}
}

//! Saves some binary data, encoded as a base64 string, with an optional name
/*! This can be called directly by users and it will automatically create a child node for
the current XML node, populate it with a base64 encoded string, and optionally name
Expand Down Expand Up @@ -361,6 +383,7 @@ namespace cereal
bool itsOutputType; //!< Controls whether type information is printed
bool itsIndent; //!< Controls whether indenting is used
bool itsSizeAttributes; //!< Controls whether lists have a size attribute
bool itsClosed = false; //!< Whether close() has been called
}; // XMLOutputArchive

// ######################################################################
Expand Down
Loading