I try to implement a JSON framework in C++ and want to make use of polymorphic concepts. I have a class JSONNode
which is kind of container that stores other JSONNode objects itself and so on. I am doing this with pointers and dynamic allocation. For exception safety I do not want to use new/delete
but go with boost shared pointer. A basic scenario for adding an element (a further json object) to a json object looks like this:
typedef boost::shared_ptr<JSONNode> JSONNodePtr;
void JSONNode::Add(JSONNodePtr nodePtr, const std::string& name)
{
this->elements[name] = nodePtr; // store in STL std::map
}
// create and add json object
JSONNodePtr obj(new JSONNode());
JSONNodePtr element(new JSONNode());
obj->Add(element, "firstElement");
For easier use I would rather do it without explicit allocation of element
and put the creation of the shared pointer into the class method Add
:
void JSONNode::Add(JSONNode* node, const std::string& name)
{
JSONNodePtr nodePtr(node);
this->elements[name] = nodePtr;
}
// create and add json object
...
obj->Add(new JSONNode, "firstElement");
But is that still exception safe? I guess not because the creation of the shared pointer is not immediately done with the allocation of the JSONNode*. What do you think? Or are there other more common ways to implement this?
No. If the construction of the
string
to pass as the other argument toAdd
throws, then the dynamic object may be leaked. It is unspecified which argument is created first.The original code ensures that the dynamic object is assigned to a smart pointer before anything else happens: the only thing that could fail is the creation of the smart pointer itself, in which case it will delete the object.
It's generally a better idea to use the
make_shared
function template, rather than usingnew
yourself. Not only does it guarantee exception safety by never exposing a naked pointer, it also makes more efficient use of memory by creating the controlled object and the shared reference count in a single block of memory.