Exception safety C++ shared pointer

1k views Asked by At

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?

1

There are 1 answers

2
Mike Seymour On BEST ANSWER

But is that still exception safe?

No. If the construction of the string to pass as the other argument to Add 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.

Or are there other more common ways to implement this?

It's generally a better idea to use the make_shared function template, rather than using new 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.

obj->Add(boost::make_shared<JSONNode>(), "firstElement"); // or std:: in C++11