3

I have got a quick question. I have the following code:

class Class1
{
    Class1();
    ~Class1();
    void func1();
private:
    char* c;

}

void Class1::func1()
{
    string s = "something";
    this->c = s.c_str();
}

will c store "something" when func1() finishes?

rodrigo
  • 94,151
  • 12
  • 143
  • 190
DalekSupreme
  • 1,493
  • 3
  • 19
  • 32
  • 5
    As soon as `s` goes out of scope `c` is invalid. – thokra Oct 24 '13 at 21:42
  • 1
    To be more precise, c will be a dangling pointer since the string will free its buffer – ltjax Oct 24 '13 at 21:43
  • 3
    @pippin1289 'testing' isn't sufficient here. Reading the data pointed to by `c` after `func1()` returns results in undefined behavior, which means that it could appear to work just fine. – bames53 Oct 24 '13 at 21:48
  • 1
    For answering this kind of question you need to read the documentation. [cppreference.com](http://en.cppreference.com/w/cpp/string/basic_string/c_str) is usually good enough for the standard library, though you might just want to get a copy of the C++ spec. – bames53 Oct 24 '13 at 21:51

4 Answers4

8

No. It will invoke undefined behavior instead. (if you dereference the pointer, anyway.) Since s is a block-scope object with automatic storage duration, it is destroyed when the function returns, and that renders the pointer returned by .c_str() invalid.


Why not use an std::string member variable instead?

  • I believe you're correct, but I'm having trouble proving it. I can imagine an implementation of the `.c_str()` member function that creates a copy of the data whose lifetime exceeds that of the `std::string` object. I think the intent is that `.c_str()` returns a pointer to the `char` array used to implement the `std::string` object (which therefore dies when the object dies), but I'd be interested to see a reference, preferably to the C++ standard, that states this explicitly. C++11 21.4.7.1 doesn't clearly say this (at least it's not clear to me). – Keith Thompson Oct 24 '13 at 22:09
  • @KeithThompson Fair request. I've found this in the [latest working draft](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf) (as of 24/10/2013, clause 21.4.7.1): "Returns: A pointer p such that `p + i == &operator[](i)` for each i in `[0,size()].` - In my read, this is undefined behavior since calling the `operator[]` member on an instance which is out of scope is undefined behavior as well, but maybe I'm misinterpreting the text. –  Oct 24 '13 at 22:15
  • Ah, I should have read that more closely. It doesn't just require the character values to be equal, it requires the *addresses* to be equal to what `operator[]` returns. That eliminates the possibility of a `.cstr()` implementation that copies the characters to a heap location, for example. – Keith Thompson Oct 24 '13 at 22:33
  • @KeithThompson: The pointer returned by `c_str()` is valid until the object is modified. Destruction counts as modification. Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()]. Once the object no longer exists the memory is gone so p is no longer available. – Martin York Oct 25 '13 at 00:51
3

s is a local variable of type std::string in Class::func1. Once func1() finishes, the string s will go out of scope.

Any pointers you have with the address of s stored in them will become dangling pointers.

digital_revenant
  • 3,274
  • 1
  • 15
  • 24
  • @H2CO3: Well, there is the _call stack_ (that used in _stack unwinding_). And `std::stack` of course! ;-) – rodrigo Oct 24 '13 at 21:48
  • @rodrigo "There is the call stack" - still not, that's still an irrelevant implementation detail. It could be implemented using any semantically correct/equivalent data structure or technique. –  Oct 24 '13 at 21:52
  • @H2CO3: Sure, but then, when an exception is thrown, you will __stack__-unwind your exotic data structure... – rodrigo Oct 24 '13 at 22:05
1

It will store a dangling pointer that you must not access. It may contain the string "something" or it may not. It doesn't matter, because accessing it is undefined behaviour, and should be avoided completely.

If you want to copy the string do this:

c = strdup( c.c_str() );

And don't forget to free(c) in ~Class1()

Beware that if you call func1 twice, you will leak memory. You probably want to initialise c to NULL in the constructor, and call free(c) before reassigning it in func1.

Surely a better approach is to store a std::string instead of a char*, which manages memory properly for you.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • 3
    `strdup`? .... oh, it's posix o.O (well it's not something I'd recommend in C++, though) – dyp Oct 24 '13 at 21:43
  • Oh I didn't realise it was posix! I've used that for years without issues. Well that makes the "use `std::string`" argument even stronger =) – paddy Oct 24 '13 at 21:47
1

The variable s, will go out of scope once control exits that block, at which point its destructor will be called.

When is an object "out of scope"?

Community
  • 1
  • 1
Christian Ternus
  • 8,406
  • 24
  • 39
  • How do you know OP's implementation has a stack? –  Oct 24 '13 at 21:45
  • @H2CO3: I think, he means `s` not `c`. – masoud Oct 24 '13 at 21:48
  • @MM. And then what? `s` could be stored anywhere as well. There's no "stack" in the language standard. Implementation is irrelevant, semantics are - everything could be reworded using just "scope", and that would be better. –  Oct 24 '13 at 21:49
  • @H2CO3 I'm genuinely curious if you think the first answer at the question I linked to is incorrect in its use of terminology. – Christian Ternus Oct 24 '13 at 21:49
  • @ChristianTernus Yes, it is incorrect. "... are stored on either the stack or on the heap" is unnecessary complexity and an assumed implementation detail, which is not helpful when one's formally explaining and reasoning about the behavior of a program. –  Oct 24 '13 at 21:50
  • @ChristianTernus Thanks for letting me know that detail anyway -- [see my comment there](http://stackoverflow.com/questions/10080935/when-is-an-object-out-of-scope/10081022#comment29055008_10081022). –  Oct 24 '13 at 21:56
  • @H2CO3 I'll be sure to use more precise terminology in the future, thanks. – Christian Ternus Oct 24 '13 at 21:57
  • @ChristianTernus You're welcome. As you may have noticed, I've revoked my apparently unjust downvote because you turned out to be misled by the other answer. –  Oct 24 '13 at 22:00