Question

The following code passes to the function modify_entry a pointer to an object of type Entry and inside the body of the function a unique_ptr adopts the raw pointer. However, the object to which the pointers point seems to live on after the function returns.

When I compile this code

#include <iostream>
#include <memory>

struct Entry {
    
    Entry(std::string name) : name_(name) { std::cout << "Constructor for " + name_ + '\n'; }
    ~Entry() { std::cout << "Destructor for " + name_ + '\n'; }
    std::string name_;
    
};

void modify_entry(Entry* e_ptr){
    
    std::cout << "Inside modify_entry()\n";
    std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";

}

int main(int argc, const char * argv[])
{
        
    Entry* entry_ptr = new Entry("John");
    modify_entry(entry_ptr);
    std::cout << "Back from modify_entry()\n";
    std::cout << entry_ptr->name_ << '\n';      // <---- line 25
            
    return 0;
    
}

with

clang version 3.4 (tags/RELEASE_34/final)

Target: x86_64-apple-darwin13.1.0

Thread model: posix

It runs without an error and the output is

Constructor for John

Inside modify_entry()

Destructor for John Doe

Back from modify_entry()

John Doe

Here, however, I get a runtime error because of line 25.

Q: Why isn't there a runtime error when I run the executable generated by clang?

I would really appreciate it if someone could clarify the situation. Please note that I am not trying to properly transfer ownership. This contrived example of bad code is the byproduct of a debugging process. make_unique and move semantics for unique_ptr etc are great, but this is not what I am asking.

Thanks in advance.

Was it helpful?

Solution

However, the object to which the pointers point seems to live on after the function returns.

The key thing here is "seems to". Actually, the Entry's lifetime ends at the end of this line:

 std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";

The unique_ptr has taken ownership of the memory, but the temporary unique_ptr's lifetime ends at the end of that statement, so it also deletes the Entry that it owns. Accessing memory that was formerly used by the object is undefined behavior. That it works on some platforms and not others is just the nature of undefined behavior.

OTHER TIPS

Q: Why isn't there a runtime error when I run the executable generated by clang?

Because undefined behaviour is undefined. The program tries to access an object after its lifetime is over. C++ defines no behaviour for such programs.

make_unique and move semantics for unique_ptr etc are great, and things like this are just yet another reason they are what you should be using.

Because what you are doing is undefined behavior, when in the main function you use a pointer to a destructed object.

The object is destructed (deleted), but you still have a pointer to where it was, dereferencing this pointer is what leads to the undefined behavior.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top