118

In one of my programs, I have to interface with some legacy code that works with const char*.

Lets say I have a structure which looks like:

struct Foo
{
  const char* server;
  const char* name;
};

My higher-level application only deals with std::string, so I thought of using std::string::c_str() to get back const char* pointers.

But what is the lifetime of c_str()?

Can I do something like this without facing undefined behavior?

{
  std::string server = "my_server";
  std::string name = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

Or am I supposed to immediately copy the result of c_str() to another place?

genpfault
  • 51,148
  • 11
  • 85
  • 139
ereOn
  • 53,676
  • 39
  • 161
  • 238
  • Happened to me when I defined a local string in a function and returned `.c_str()`. I didn't understand why sometimes I get only parts of the string, until I understood that the `const char*` does not live forever, but until the string is destroyed – SomethingSomething Dec 02 '14 at 17:34

7 Answers7

96

The c_str() result becomes invalid if the std::string is destroyed or if a non-const member function of the string is called. So, usually you will want to make a copy of it if you need to keep it around.

In the case of your example, it appears that the results of c_str() are used safely, because the strings are not modified while in that scope. (However, we don't know what use_foo() or ~Foo() might be doing with those values; if they copy the strings elsewhere, then they should do a true copy, and not just copy the char pointers.)

Kristopher Johnson
  • 81,409
  • 55
  • 245
  • 302
  • c_str() pointer could be invalid if the std::string object is a automatic object going out of scope or in call to a thread creating function. – GuruM Oct 16 '12 at 15:49
  • Can you please explain `non-const member function of the string is called.`? – Mathew Kurian Dec 24 '13 at 11:03
  • 4
    A "non-const member function" is any member function that is not marked with the `const` keyword. Such a function might mutate the string's contents, in which case the string might need to reallocate the memory for the null-terminated version of the string returned by `c_str()`. For example, `size()` and `length()` are `const`, so you can call them without worrying about the string changing, but `clear()` is not `const`. – Kristopher Johnson Dec 24 '13 at 20:16
27

Technically your code is fine.

BUT you have written in such a way that makes it easy to break for somebody that does not know the code. For c_str() the only safe usage is when you pass it as a parameter to a function. Otherwise you open yourself up-to maintenance problems.

Example 1:

{
  std::string server = "my_server";
  std::string name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  //
  // Imagine this is a long function
  // Now a maintainer can easily come along and see name and server
  // and would never expect that these values need to be maintained as
  // const values so why not re-use them

  name += "Martin";
  // Oops now its broken.

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

So for maintenance make it obvious:

Better solution:

{
  // Now they can't be changed.
  std::string const server = "my_server";
  std::string const name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  use_foo(foo);    
}

But if you have const strings you don't actually need them:

{
  char const* server = "my_server";
  char const* name   = "my_name";

  Foo foo;
  foo.server = server;
  foo.name   = name;

  use_foo(foo);
}

OK. For some reason you want them as strings:
Why not use them only in the call:

{
  std::string server = "my_server";
  std::string name = "my_name";

  // guaranteed not to be modified now!!!     
  use_foo(Foo(server.c_str(), name.c_str());
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
8

It is valid until one of the following happens to the corresponding string object:

  • the object is destroyed
  • the object is modified

You're fine with your code unless you modify those string objects after c_str()s are copied into foo but before use_foo() is called.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
4

Return value of c_str() is valid only until the next call of a nonconstant member function for the same string

DumbCoder
  • 5,696
  • 3
  • 29
  • 40
3

The const char* returned from c_str() is only valid until the next non-const call to the std::string object. In this case you're fine because your std::string is still in scope for the lifetime of Foo and you aren't doing any other operations that would change the string while using foo.

AJG85
  • 15,849
  • 13
  • 42
  • 50
2

For completeness, here's a reference and quotation from cppreference.com:

The pointer obtained from c_str() may be invalidated by:

  • Passing a non-const reference to the string to any standard library function, or
  • Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().
Community
  • 1
  • 1
Victor Sergienko
  • 13,115
  • 3
  • 57
  • 91
2

As long as the string isn't destroyed or modified, using c_str() is OK. If the string is modified using a previously returned c_str() is implementation defined.

CharlesB
  • 86,532
  • 28
  • 194
  • 218