Reputation: 836
This code compiles and executes. I know that we have undefined behaviour in the first case. But what happens exactly in the second case?
#include <string>
#include <iostream>
#include <cstdio>
std::string foo() {
return "HELLO";
}
void bar(const char *p) {
std::printf("%s\n", p);
}
int main() {
// FIRST CASE:
// I know this is bad, because after the assignment
// the variable returned by foo() is destroyed and we
// have a bad reference.
const std::string &s = foo();
bar(s.c_str());
// SECOND CASE:
// But what about that ? I don't know exactly if the
// object is alive after the call to c_str()
bar(foo().c_str());
return 0;
}
GCC output is in both cases "HELLO" but I think that's because it's not cleaning the raw memory.
In the second case when exactly is the temporary object destroyed?
Upvotes: 13
Views: 1762
Reputation: 30992
Both of those cases are well-defined. To see a problematic case, store the result of c_str()
until after the std::string
is destructed:
#include <string>
#include <cstdio>
std::string foo() {
return "HELLO";
}
void bar(const char *p) {
std::printf("%s\n", p);
}
int main() {
{
// FIRST CASE:
// This is okay, because the reference is const, so the object is alive
// until s goes out of scope.
const std::string &s = foo();
bar(s.c_str());
}
{
// VARIANT FIRST CASE:
// This is bad; the pointer is dangling
const char *s = foo().c_str();
bar(s);
}
{
// SECOND CASE:
// Is the object still alive after the call to c_str()? Yes, it's alive
// until after bar() has returned.
bar(foo().c_str());
}
return 0;
}
When I run this under Valgrind, it gives errors only for the variant case (with const char *s
):
==9981== Invalid read of size 1
==9981== at 0x4C2E0E2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9981== by 0x543EC7B: puts (ioputs.c:36)
==9981== by 0x400937: bar(char const*) (37946437.cpp:9)
==9981== by 0x4009AA: main (37946437.cpp:25)
==9981== Address 0x5aabcf8 is 24 bytes inside a block of size 30 free'd
==9981== at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9981== by 0x4F058FD: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22)
==9981== by 0x40099E: main (37946437.cpp:24)
Upvotes: 7
Reputation: 65770
Actually, both of these cases are okay.
In the first case, binding the temporary to a const
reference extends its lifetime to that of s
. So it won't be destroyed until main
exits.
In the second case, the temporary is destroyed after the end of the full-expression containing it. In this case, it is the function call. If you stored that C string anywhere which outlived bar
and then tried to access it, then you're due a date with undefined behaviour.
Upvotes: 21