10

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?

5 Answers 5

25

You can use shared_ptr from C++11 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.

Sign up to request clarification or add additional context in comments.

1 Comment

yes, except that we don't normally use Boost, but I can create such a class myself. Thanks
3

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.

Comments

1

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;
}

3 Comments

Apart from the code does not compile (Look at L""). Its not exception safe. You dont guarantee that p will be released.
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.
Phew! Now that leak is gone also. Thanks for pointing it out.
1

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.

Comments

0

We commonly use ScopeGuard for these cases:

string foo()
{
  char *p = get_string();
  ScopeGuard sg = MakeGuard(&free, p);
  string str( p );
  return str;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.