This question already has answers here:
Lifetime of temporaries
(2 answers)
Closed 9 years ago.
I have tested this code:
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int main()
{
string s1("a"),s2("b");
const char * s = (s1+s2).c_str();
printf("%s\n",s);
}
It returns "ab".
As far as I know, since (s1 +s2) is a temporary object and may disappear somehow (I have no idea about that), then const char * s may point to undefined memory and may get dumped.
So is it safe to use the .c_str() like that?
It's not safe in your example. It's safe however in
printf("%s\n", (a + b).c_str());
The reason is that temporary values (like the result of a + b) are destroyed at the end of the full expression. In your example the const char * survives the full expression containing the temporary and dereferencing it is undefined behaviour.
The worst part of "undefined behaviour" is that things may apparently work anyway... (UB code crashes only if you're making your demo in front of a vast audience that includes your parents ;-) )
In that example we can just quote the standard:
12.2 Temporary objects [class.temporary]
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.
That is after the semicolon of your line:
const char * s = (s1+s2).c_str(); // <- Here
So here:
printf("%s\n",s); // This line will now cause undefined behaviour.
Why? Because as your object is destructed, you don't know anymore what is at this place now...
The bad thing here is that, with Undefined behaviour, your program may seem to work at the first time, but... It will crash for sure at the worst time...
You can do:
printf( "%s\n", (s1+s2).c_str() );
It will work because the object is not destructed yet (remember, after the semicolon...).
It's not safe, but you can easily assign to a new variable, and the pointer will be safe in the scope of that variable:
string s1("a"), s2("b") , s3;
s3 = s1 + s2;
printf("%s\n", s3.c_str());
//other operations with s3
Like most programming constructs, it's "safe" if you use it correctly, and it's not "safe" if you're sloppy. In this case, using it correctly means paying attention to object lifetimes. The + operator creates a temporary object which gets destroyed at the end of the statement, and the returned const char* is no longer valid after the statement that created it. So you can pass the result of c_str() directly to a function, but you can't save the pointer and use it later.
Related
This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
Consider the following code:
I declare a new reference end assign it to value a via const_cast. Then I just increase the reference value print the addresses and values.
#include <iostream>
using namespace std;
int main()
{
const int a = 7;
int &b = const_cast<int&>(a);
++b;
cout<<"Addresses "<<&a<<" "<<&b<<endl;
cout<<"Values "<<a<<" "<<b<<endl;
}
//output
Addresses 0x7fff11f8e30c 0x7fff11f8e30c
Values 7 8
How can i have 2 different values in the same address??
Because modifying a variable declared to be const is undefined behavior, literally anything can happen.
Modifying a constant object gives undefined behaviour, so your program could (in principle) do anything.
One reason for leaving this behaviour undefined is to allow the optimisation of replacing a constant variable with its value (since you've stated that the value can never change). That's what is happening here: a is replaced with the value 7 at compile time, and so will keep that value whatever you try to do to it at run time.
Even though const_cast may remove constness from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const invokes undefined behavior.
check out the example here for more illustration:
http://en.cppreference.com/w/cpp/language/const_cast
Any attempt to modify an object that is itself declared const by means of const_cast results in undefined behavior according to the ISO C++ Standard.
When the we refer "const object", it intends to say that the memory where the object is located may be write-protected. That is, a variable or expression of const type may denote an object stored in write-protected memory and any attempt to modify the object results in undefined behavior
EDIT: Refer this site for more info
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1994/N0571.asc
We are in a hot discussion with my friends about the code:
#include <iostream>
#include <string>
using namespace std;
string getString() {
return string("Hello, world!");
}
int main() {
char const * str = getString().c_str();
std::cout << str << "\n";
return 0;
}
This code produces different outputs on g++, clang and vc++:
g++ and clang output is the same:
Hello, world!
However vc++ outputs nothing (or just spaces):
What behavior is correct? Is this may be a change in standard according to temporaries lifetime ?
As far as I can see by reading IR of clang++, it works as following:
store `getString()`'s return value in %1
std::cout << %1.c_str() << "\n";
destruct %1
Personally, I think gcc works this way too (I've tested it with rvo/move verbosity (custom ctors and dtors which prints to std::cout). Why does vc++ works other way?
clang = Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
g++ = gcc version 4.9.2 (Debian 4.9.2-10)
Your program has undefined behaviour! You are "printing" a dangling pointer.
The result of getString(), a temporary string, lives no longer than that const char* declaration; accordingly neither does the result of invoking c_str() on that temporary.
So both compilers are "correct"; it is you and your friends who are wrong.
This is why we shall not store the result of std::string::c_str(), unless we really, really need to.
Both are right, undefined behaviour is undefined.
char const * str = getString().c_str();
getString() returns a temporary, which will be destroyed at the end of the full expression which contains it. So after that line is finished, str is an invalid pointer and trying to inspect it will plunge you into the land of undefined behaviour.
Some standards quotes, as requested (from N4140):
[class.temporary]/3: Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created.
basic_string::c_str is specified like so:
[string.accessors]/1: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
Since strings have their contents stored contiguously ([string.require]/4) this essentially means "return a pointer to the start of the buffer".
Obviously when a std::string is destructed it will reclaim any memory which was allocated, making that pointer invalid (if your friends don't believe that, they have other problems).
That is undefined behavior so anything can happen (including printing the string "correctly").
Making things "working" anyway happens quite often with UB, unless the program is actually running on a paying customer's computer or if it's shown on the big screen in front of a vast audience ;-)
The problem is that you're taking a const char * pointing inside a temporary object that is destroyed before your use of the pointer.
Note that this is not the same situation as with:
const std::string& str = getString(); // Returns a temporary
std::cout << str << "\n";
because in this case instead there is a very specific rule about references bound to temporaries in the C++ standard. In this case the lifetime of the temporary will be extended until the reference str is also destroyed. The rule only applies to references and only if directly bound to the temporary or to a sub-object of the temporary (like const std::string& s = getObj().s;) and not to the result of calling methods of a temporary object.
This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
Consider the following code:
I declare a new reference end assign it to value a via const_cast. Then I just increase the reference value print the addresses and values.
#include <iostream>
using namespace std;
int main()
{
const int a = 7;
int &b = const_cast<int&>(a);
++b;
cout<<"Addresses "<<&a<<" "<<&b<<endl;
cout<<"Values "<<a<<" "<<b<<endl;
}
//output
Addresses 0x7fff11f8e30c 0x7fff11f8e30c
Values 7 8
How can i have 2 different values in the same address??
Because modifying a variable declared to be const is undefined behavior, literally anything can happen.
Modifying a constant object gives undefined behaviour, so your program could (in principle) do anything.
One reason for leaving this behaviour undefined is to allow the optimisation of replacing a constant variable with its value (since you've stated that the value can never change). That's what is happening here: a is replaced with the value 7 at compile time, and so will keep that value whatever you try to do to it at run time.
Even though const_cast may remove constness from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const invokes undefined behavior.
check out the example here for more illustration:
http://en.cppreference.com/w/cpp/language/const_cast
Any attempt to modify an object that is itself declared const by means of const_cast results in undefined behavior according to the ISO C++ Standard.
When the we refer "const object", it intends to say that the memory where the object is located may be write-protected. That is, a variable or expression of const type may denote an object stored in write-protected memory and any attempt to modify the object results in undefined behavior
EDIT: Refer this site for more info
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1994/N0571.asc
This question already has answers here:
Why does this work: returning C string literal from std::string function and calling c_str()
(9 answers)
Closed 9 years ago.
For Code:
stringstream ss("012345678901234567890123456789012345678901234567890123456789");
some articles said it is wrong for followed usage due to ss.str return temp object and will destructered before call .c_str();
const char* cstr2 = ss.str().c_str();
but I run the example, there is no problem? how to understand?
But I run the example, there is no problem?
In fact, there's nothing wrong in the expression:
const char* cstr2 = ss.str().c_str();
The temporary (copy) object returned by ss.str() will live long enough to let you get the underlying c-string with c_str().
Of course by the end of the expression you'll have a const char pointer to an object that is probably deallocated (this depends heavily on the std::basic_string implementation).
Therefore this is likely not a good idea. What you should do instead is:
auto x = ss.str();
const char* cstr2 = x.c_str();
The above code won't get you any trouble, since the returned value of str() is now being copied/is not a temporary anymore, and the access to x.c_str() will give you a valid pointer.
Yet another wonderful C++ landmine.
Basically, your pointer references a block of memory (C string) that is referencing a temporary copy (string) of whatever was in the stream at the time you did the double affectation.
str() returns a temporary object.
Life expectancy of temporary objects is rather short. Either someone takes a reference to them immediately (e.g. string& s = ss.str()) or they die at the end of the statement they were born in.
However, the compiler allows to get a reference to the same block of memory through c_str(), but indirectly, so it flies under the compiler's radar. What a pity.
So your pointer will indeed be valid at the time c_str gets it, but just for about as long as if you did something like this in plain old C:
const char * cstr2;
{
char ss_str[100]; // str() return value is dynamically created
char * c_str = &ss_str_[10]; // c_str() takes a reference to some part of it
cstr2 = c_str; // cstr2 takes an indirect reference to str() ret. val.
} // compiler pulls the plug on str() ret. val.
So, right after the end of this very statement, c_str is already referencing the cadaver of whatever string str() returned.
Now since temporary objects are allocated on the stack, you may well never notice the problem. Object deallocation in itself will likely not modify the defunct string value, but as soon as the compiler will reuse this bit of stack, the proverbial guru will have something to meditate over.
First of all, it's important to understand that attempting to make use of a dangling pointer is not guaranteed to fail in any obvious way. It can appear to "work" just as often as it can crash spectacularly.
Secondly, yes, that code is invalid and you shouldn't do it. The stringstream's lifetime is not important because std::stringstream::str() returns by value (i.e. a copy of the internal buffer), but then you're still subject to that string going out of scope before you can make use of its C-string pointer.
Is this well defined behavior?
const char* p = (std::string("Hello") + std::string("World")).c_str();
std::cout << p;
I am not sure. Reasons?
No, this is undefined behavior. Both std::string temporaries and the temporary returned by operator+ only live until the end of the initialization of your const char* (end of full expression). Then they are destroyed and p points to uncertain memory.
No the behaviour is undefined because p points to deallocated storage in std::cout << p;
A temporary is created to hold std::string("Hello") + std::string("World"). C-style string is then retrived from that object. At the end of the expression that temporary is destroyed leaving p pointing to a deallocated storage.
Using p then invokes Undefined Behavior.
12.2/4 says
There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when an expression appears as an initializer for a declarator defining an object. In that context, the temporary that holds the result of the expression shall persist until the object’s
initialization is complete.
....
it won't compile because of a missing semi-colon:
const char* p = (std::string("Hello") + std::string("World")).c_str(); //<< important here
std::cout << p;
NOW the rule applies that the temporary is deleted at the end of the expression it is used in, which is at the semicolon. So you have a pointer to deleted memory which causes undefined behaviour.
I recently read this excellent book http://www.amazon.co.uk/Gotchas-Avoiding-Addison-Wesley-Professional-Computing/dp/0321125185/ref and if I recall correctly this is pretty much one of the examples given there.
I believe the data returned from c_str is only valid as long as the string object that returned it is live. The string objects in your example are only live for the duration of the expression.