I have a bit of code where I parse a json file, edit it, and save it again. The code works fine as long as I don't create an object and then remove a member. Doing those two steps causes an assertion in the object where the member was removed when writing again. I've compiled a small example to show what I mean:
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/istreamwrapper.h"
#include <iostream>
#include <fstream>
int main( int argc, char *argv[] )
{
rapidjson::Document document;
{
std::ifstream file( "test.json" );
rapidjson::IStreamWrapper file_wrapper( file );
// Now load it up
if( document.ParseStream( file_wrapper ).HasParseError() )
{
std::cout << "Configuration: Error parsing JSON." << std::endl;
return( EXIT_FAILURE );
}
}
// Now move some things around
{
auto &allocator = document.GetAllocator();
// Shorthand
auto &one = document[ "one" ];
// Move each
if( one.HasMember( "fruit" ) and one[ "fruit" ].IsString() )
{
const std::string &s = one[ "fruit" ].GetString();
document.AddMember( "fruit", s, allocator );
one.RemoveMember( "fruit" );
}
if( one.HasMember( "pear" ) and one[ "pear" ].IsString() )
{
std::string s = one[ "pear" ].GetString();
rapidjson::Value value( rapidjson::kObjectType );
value.AddMember( "pear", s, allocator );
document.AddMember( "sugar", std::move( value ), allocator );
one.RemoveMember( "pear" );
}
if( one.HasMember( "apple" ) and one[ "apple" ].IsString() )
{
const std::string &s = one[ "apple" ].GetString();
document.AddMember( "apple", s, allocator );
one.RemoveMember( "apple" );
}
}
// Write it out
rapidjson::StringBuffer sb;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer( sb );
// Write from the document
document.Accept( writer );
// Open the file
std::ofstream file( "test-out.json" );
// Now write
file << sb.GetString();
}
Parsing this test.json file:
{
"one" : {
"fruit": "box",
"apple": "plane",
"pear" : "quincy"
},
"two" : {
"french" : "pub"
}
}
Will produce this output
report: rapidjson/document.h:1878: bool rapidjson::GenericValue<Encoding, Allocator>::Accept(Handler&) const [with Handler = rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<> > >; Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>]: Assertion `m->name.IsString()' failed.
Aborted
If I take out all of the one.RemoveMember( ... ) lines the code will work. If I remove the block about adding an object it will work. RemoveMember and adding an object can't seem to co-exist.
How can this be sorted out?
Here is a backtrace from gdb:
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007ffff7a65535 in __GI_abort () at abort.c:79
#2 0x00007ffff7a6540f in __assert_fail_base (fmt=0x7ffff7bdeea8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x555555562181 "m->name.IsString()", file=0x55555556212c "rapidjson/document.h", line=1878,
function=<optimized out>) at assert.c:92
#3 0x00007ffff7a73852 in __GI___assert_fail (assertion=0x555555562181 "m->name.IsString()", file=0x55555556212c "rapidjson/document.h", line=1878,
function=0x555555564ec0 <rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>&) const::__PRETTY_FUNCTION__> "bool rapidjson::GenericValue<Encoding, Allocator>::Accept(Handler&) const [with Handler = rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<> > >; Encoding = rapidjson::UTF8<>; Al"...) at assert.c:101
#4 0x000055555555a22d in bool rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>&) const ()
#5 0x000055555555a2c5 in bool rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >::Accept<rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u> >(rapidjson::PrettyWriter<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>&) const ()
#6 0x00005555555568df in main ()