从函数返回 std::pair<std::shared_ptr<A>、std::unique_ptr<B>&> 会导致异常
Returning an std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> from a function results in weirdness
我无法理解以下代码示例中在幕后执行的(对我来说是复杂的)机制:
#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();
}
我用 GCC 和 Clang 编译了代码,结果相似:
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
很明显,std::unique_pointer引用的地址(当然还有它的值)和FuncA内部不一样,但是std::shared_pointer的地址和值没有变化.
这里发生了什么,可以做些什么(如果有的话)来使引用传递正确?
是否由于从 FuncA 返回而在 std::unique_ptr 上执行了某种形式的复制构造函数?
std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
// ...
std::unique_ptr<B> b = std::make_unique<B>();
// ...
return {a,b};
}
创建了一个本地 std::unique_ptr<B>
并返回对它的引用作为对中的第二个元素。这是一个悬空引用,稍后会被访问,从而给程序带来未定义的行为。
我无法理解以下代码示例中在幕后执行的(对我来说是复杂的)机制:
#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();
}
我用 GCC 和 Clang 编译了代码,结果相似:
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
很明显,std::unique_pointer引用的地址(当然还有它的值)和FuncA内部不一样,但是std::shared_pointer的地址和值没有变化.
这里发生了什么,可以做些什么(如果有的话)来使引用传递正确?
是否由于从 FuncA 返回而在 std::unique_ptr 上执行了某种形式的复制构造函数?
std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
// ...
std::unique_ptr<B> b = std::make_unique<B>();
// ...
return {a,b};
}
创建了一个本地 std::unique_ptr<B>
并返回对它的引用作为对中的第二个元素。这是一个悬空引用,稍后会被访问,从而给程序带来未定义的行为。