1
std::vector<unique_ptr<int>> v;
v.push_back(std::make_unique<int>(1));

unique_ptr<int>& rp0 = v[0];
cout << "rp1="<<rp0.get()<<"\n";
cout << "*rp1="<<*rp0<<"\n";

v.push_back(std::make_unique<int>(2));

cout << "rp1="<<rp0.get()<<"\n";
cout << "*rp1="<<*rp0<<"\n";

Why the result from the second print is not the same as the first one?

rp1=0x1783c20
*rp1=1
rp1=0
Segmentation fault (core dumped)
Oblivion
  • 7,176
  • 2
  • 14
  • 33

2 Answers2

5

As per: https://en.cppreference.com/w/cpp/container/vector/push_back and I quote:

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

So basically when doing the push_back the vector creates, if needed, a new buffer of bigger capacity, moves all the std::unique_ptr from the old buffer to the new, add the new unique_ptr and deletes the old buffer.

You have a reference to an element in the old buffer, which dangles. A dangling reference is undefined behavior and everything can happen, for example you can have garbage data being printed or a crash.

Edit: I explain the issue, Oblivion, in their answer, explains a possible remediation using shared_ptrwhich might be appropriate or not given the use case which is unknown.

2

@CuriouslyRecurringThoughts gave a thorough explanation on why you have dangling reference, I just give a possible solution.

One method to avoid the dangling reference in your example is using shared_ptr instead of a reference to a unique_ptr:

#include<iostream>
#include <vector>
#include <memory>

int main()
{
    std::vector<std::shared_ptr<int>> v;
    v.push_back(std::make_shared<int>(1));

    std::shared_ptr<int> rp0 = v[0];
    std::cout << "rp1="<<rp0.get()<<"\n";
    std::cout << "*rp1="<<*rp0<<"\n";

    v.push_back(std::make_shared<int>(2));

    std::cout << "rp1="<<rp0.get()<<"\n";
    std::cout << "*rp1="<<*rp0<<"\n";
}

Live

Oblivion
  • 7,176
  • 2
  • 14
  • 33