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?
CodePudding user response:
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.