1

I don't think I've understood the concept of smart pointers correctly.

Have a look at this MWE:

// Example program
#include <iostream>
#include <memory>
#include <string>

struct P{
    float x, y;
    P() : x(0.f), y(0.f){}
    P(float x, float y) : x(x), y(y){}
    P(P&& q) : x(q.x), y(q.y){}
    P& operator=(P&& q){
        x = q.x;
        y = q.y;
        return *this;
    }
    P& operator=(const P&) = delete;
    P(const P&) = delete;

};

std::ostream& operator<<(std::ostream& out, const P& p){ out << p.x << " / " << p.y; return out;}

int main(){    
    P p1{1.f, 0.f};
    P p2{2.f, 0.f};

    std::unique_ptr<P> p1Ptr(std::make_unique<P>(std::move(p1)));
    P* p2Ptr = &p2;

    p1 = std::move(P{1.f, 1.f});
    p2 = std::move(P{2.f, 2.f});

    std::cout << " p1: " << p1 << "\n";
    std::cout << "*p1: " << *p1Ptr << "\n";
    std::cout << "*p1: " << *(p1Ptr.get()) << "\n";
    std::cout << " p2: " << p2 << "\n";
    std::cout << "*p2: " << *p2Ptr << std::endl; 
}

Output:

p1: 1 / 1
*p1: 1 / 0
*p1: 1 / 0
p2: 2 / 2
*p2: 2 / 2

I would have expected the std::unique_ptr to also see the value change of p1. However, this is not the case. How can I achieve this?

Stack Danny
  • 7,754
  • 2
  • 26
  • 55
infinitezero
  • 1,610
  • 3
  • 14
  • 29
  • The pointer `p1ptr` is pointing to a completely different object of type `P`. It doesn't point to or reference `p1` at all. `*p1ptr` and `p1` are two distinct and separate objects. – Some programmer dude Jul 02 '19 at 12:09
  • 1
    note that the moves are redundant, `p1 = P{1.f, 1.f};` is already a move assignment. – Caleth Jul 02 '19 at 12:21
  • This is XY problem - why do you need `std::unique_ptr` to point to existing object? It defeats its purpose. – Slava Jul 02 '19 at 12:27
  • @Slava if you are trying to own a struct that doesn't have a ctor defined, then you have no option but to point to an existing object? https://stackoverflow.com/questions/55141594/make-unique-with-brace-initialization – simplename Jan 12 '22 at 17:15

1 Answers1

4

p1Ptr does not actually point at the object p1. It points at the unnamed object which was created by std::make_unique using the constructor P(P&&).

It doesn't make sense to have a std::unique_ptr<T> point at an object defined local to a function block. The whole reason for a unique_ptr is that it is the single owner of the object it points at in some way. Since you're using the default deleter, that ownership means that the unique_ptr will delete a pointer to its object, attempting to end its lifetime. But a function local object already has its lifetime "owned" by the function block, and will automatically be destroyed when execution leaves that block; it's not valid to delete a pointer to such an object.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • So if I need pointers to elements in a vector, it is better to use raw pointers? – infinitezero Jul 02 '19 at 12:49
  • @infinitezero smart pointers represent ownership, either unique or shared, if you just point but do not own use raw pointers. Btw it is not a good idea to have pointers to elements in a vector due to reallocation. – Slava Jul 02 '19 at 13:02
  • The elements in a `std::vector` are similarly already "owned", this time by the `vector`. – aschepler Jul 02 '19 at 13:31