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?
A destructor is a member function that is invoked automatically when the object goes out of scope or is explicitly destroyed by a call to delete . A destructor has the same name as the class, preceded by a tilde ( ~ ).
A temporary object is an unnamed object created by the compiler to store a temporary value.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With