简体   繁体   中英

create std::string from char* in a safe way

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?

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.

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.

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.

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

We commonly use ScopeGuard for these cases:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM