Ad

Returning An Std::pair, Std::unique_ptr&> From A Function Results In Weirdness

- 1 answer

I'm having trouble understanding the (to me intricate) mechanisms executed behind the scenes in the following code example:

#include <utility>
#include <memory>
#include <iostream>

struct A {int a;};
struct B {int b;};

std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::unique_ptr<B> b = std::make_unique<B>();

    a->a = 12; b->b = 13;

    std::cout << "FuncA a: " << a.get() << std::endl;
    std::cout << "FuncA b: " << b.get() << std::endl;

    std::cout << "FuncA a.a: " << a->a << std::endl;
    std::cout << "FuncA b.b: " << b->b << std::endl;

    return {a,b};
}

void FuncC(std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> input) {
  std::cout << "FuncC a: " << input.first.get()  << std::endl;
  std::cout << "FuncC b: " << input.second.get() << std::endl;

  std::cout << "FuncC a.a: " << input.first->a  << std::endl;
  std::cout << "FuncC b.b: " << input.second->b << std::endl;
}

void FuncB() {
  auto ret = FuncA();
  
  std::cout << "FuncB a: " << ret.first.get()  << std::endl;
  std::cout << "FuncB b: " << ret.second.get() << std::endl;

  std::cout << "FuncC a.a: " << ret.first->a  << std::endl;
  std::cout << "FuncC b.b: " << ret.second->b << std::endl;

  FuncC(ret);
}

int main(){
  FuncB();
}

I've compiled the code with both GCC and Clang which give similar results:

FuncA a: 0xfeaec0
FuncA b: 0xfeaed0
FuncA a.a: 12
FuncA b.b: 13
FuncB a: 0xfeaec0
FuncB b: 0x7ffd1c8e4a00
FuncC a.a: 12
FuncC b.b: 479087264
FuncC a: 0xfeaec0
FuncC b: 0x406100
FuncC a.a: 12
FuncC b.b: 1449378512

As is clearly visible, the address of the std::unique_pointer reference (and of course also its value) are not the same as within FuncA, but the address and value of the std::shared_pointer are unchanged.

What's happening here, and what (if anything) could be done to make the reference-passing correct?

Is some form of copy-constructor being executed on the std::unique_ptr as a result of returning from FuncA?

Ad

Answer

std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
    // ...
    std::unique_ptr<B> b = std::make_unique<B>();
    // ...
    return {a,b};
}

A local std::unique_ptr<B> is created and a reference to it is returned as the second element in the pair. This is a dangling reference and is later accessed, giving the program undefined behaviour.

Ad
source: stackoverflow.com
Ad