views:

1738

answers:

5

I have a char* p, which points to a 0-terminated string.

How do I create a C++ string from it in an exception-safe way?

Here is an unsafe version:

string foo()
{
  char *p = get_string();

  string str( p );
  free( p );
  return str;
}

An obvious solution would be to try-catch - any easier ways?

+18  A: 

You can use shared_ptr from TR1 or Boost:

string
foo()
{
    shared_ptr<char> p(get_string(), &free);
    string str(p.get());
    return str;
}

This uses a very specific feature of shared_ptr not available in auto_ptr or anything else, namely the ability to specify a custom deleter; in this case, I'm using free as the deleter.

Chris Jester-Young
yes, except that we don't normally use Boost, but I can create such a class myself. Thanks
n-alexander
+1  A: 

Yup - stack-based unwinding. Modern C++ Design has the general solution but in this case you can use

struct Cleanup {
        void* toFree;
        Cleanup(void* toFree) : toFree(toFree) {}
        ~Cleanup() { free(toFree); }
    private:
        Cleanup(Cleanup&);
        void operator=(Cleanup&);
};

No matter what happens with your std::string, free(toFree) will be called when your Cleanup object goes out of scope.

MSalters
+1  A: 

Well, p does not point to a 0-terminated string if get_string() returns NULL; that's the problem here, since the std::string constructors that take a pointer to 0-terminated C string cannot deal with NULL, which is as much a 0-terminated C string as two dozens of bananas are.

So, if get_string() is your own function, as opposed to a library function, then maybe you should make sure that it cannot return NULL. You could for instance let it return the sought std::string itself, since it knows it's own state. Otherwise, I'd do this, using the Cleanup from this answer as a helper to guarantee that p cannot leak (as suggested by Martin York in a comment):

string foo()
{
    const char* p = get_string();
    const Cleanup cleanup(p);
    const std::string str(p != NULL ? p : "");

    return str;
}
Johann Gerell
Apart from the code does not compile (Look at L""). Its not exception safe. You dont guarantee that p will be released.
Martin York
Ah! Sorry about that - I only develop for Windows CE based devices, and there we only have Unicode strings, so the 'L' prefix is hammered into my spine when I write code. That case is now fixed.
Johann Gerell
Phew! Now that leak is gone also. Thanks for pointing it out.
Johann Gerell
A: 

We commonly use ScopeGuard for these cases:

string foo()
{
  char *p = get_string();
  ScopeGuard sg = MakeGuard(&free, p);
  string str( p );
  return str;
}
Andreas Magnusson
+3  A: 

Can I ask you what exception you are expecting in your example?

On many platforms (Linux, AIX) new or malloc will never fail and your app will get killed by the os if you run out of memory.

See this link: What happens when Linux runs out of memory.

James Dean