Search code examples
c++segmentation-faultunique-ptr

use method reset of unique_prt:free(): invalid pointer


When I use reset to rebind the unique_ptr, something bad happens but when use std::make_unique, everything is ok.

int main() {
    unique_ptr<string> p= nullptr;
    auto l=[&p]()->void{
        static string x {"1111"};
        cout<<x<<endl;
        //p = std::make_unique<string>(x);// compile ok
        p.reset(&x);//compile error free():invalid pointer; 
        cout<<p.get()<<endl;
        return;
    };
    l();
    cout<<p->length()<<endl;
    cout<<p.get()<<endl;
    return 0;
}

enter image description here

I think that when the reset method is called, the string object is not really handed over to the unique_ptr management. When leaving the scope, the dtor is called twice


Solution

  • Both variants do compile without errors (provided one adds the missing parts). Your code invokes undefined behavior and likely crashes at runtime.

    When you use std::make_unique like this:

    p = std::make_unique<string>(x);
    

    Then std::make_unique constructs a std::unique_ptr that manages the lifetime of a std::string that is constructed as a copy of x. You now have two strings, x and the one managed by p.

    When you use reset like this:

    p.reset(&x);
    

    You tell p to take ownership of x. However, x is not dynamically allocated. It makes no sense to transfer its ownership to a smart pointer. When ps destructor is called it will attempt to delete &x but x was not allocated via new, hence there is undefined behavior. When the program terminates the lifetime of the static string ends and x is destroyed (again).


    I think that when the reset method is called, the string object is not really handed over to the unique_ptr management.

    Yes it is. And that is the problem.


    It is not clear what the actual purpose of the code is. To return string from the lambda:

    #include <string>
    #include <iostream>
    
    int main() {
        auto l=[](){
            std::string x {"1111"};
            std::cout << x << std::endl;        
            return x;
        };
        auto p = l();
        std::cout << p.length() << std::endl;
    }