是的,这是一个真正的问题。您的程序的行为未定义。 c 是与b 引用的指针不同的对象,它的生命周期在doWarning 的末尾结束。这两个指针指向同一个 A 对象 (d),但这并不意味着它们是同一个对象。
为了说明,我将或多或少地逐行使用图表:
A d;
auto m = doWarning(&d);
这将创建一个名为d 的A 对象,并将指向该对象的匿名指针传递给doWarning。稍后我会到达m,但现在游戏中的对象看起来像这样:
d
┌─────┐ ┌─────┐
│ │ │ │
│ A* ├──────►│ A │
│ │ │ │
└─────┘ └─────┘
template<typename T>
T const& doWarning(T const& b)
{
在这里,T 将被推断为 A*,因为这是传递给它的。
doWarning 通过引用接受其参数,因此b 的类型将为A* const &。也就是说,b 是从main 指向d 的匿名指针的引用:
b d
┌───────────┐ ┌─────┐ ┌─────┐
│ │ │ │ │ │
│ A* const& ├──────►│ A* ├──────►│ A │
│ │ │ │ │ │
└───────────┘ └─────┘ └─────┘
A* c = returningLocalPointer(b);
在这里创建另一个指针c,它指向与b 相同的对象。我不会看returningLocalPointer,因为它或多或少无关紧要。这条线可以用A* c = b; 代替,什么都不会改变。您的对象现在看起来像这样:
b d
┌───────────┐ ┌─────┐ ┌─────┐
│ │ │ │ │ │
│ A* const& ├──────►│ A* ├──────►│ A │
│ │ │ │ │ │
└───────────┘ └─────┘ └─────┘
▲
c │
┌─────┐ │
│ │ │
│ A* ├──────────┘
│ │
└─────┘
如您所见,c 与b 引用的对象不同。
return c;
由于doWarning返回一个A* const&(因为T是A*),这初始化返回值以引用局部变量c:
b d
┌───────────┐ ┌─────┐ ┌─────┐
│ │ │ │ │ │
│ A* const& ├──────►│ A* ├──────►│ A │
│ │ │ │ │ │
└───────────┘ └─────┘ └─────┘
▲
return value c │
┌───────────┐ ┌─────┐ │
│ │ │ │ │
│ A* const& ├──────►│ A* ├──────────┘
│ │ │ │
└───────────┘ └─────┘
}
现在doWarning 结束,因此它的局部变量c 超出范围并且它的生命周期结束。这使得doWarning 的返回值悬空:
b d
┌───────────┐ ┌─────┐ ┌─────┐
│ │ │ │ │ │
│ A* const& ├──────►│ A* ├──────►│ A │
│ │ │ │ │ │
└───────────┘ └─────┘ └─────┘
return value
┌───────────┐
│ │
│ A* const& ├──────► Nothing here anymore
│ │
└───────────┘
auto m = doWarning(&d);
现在我们回到m。 auto 本身永远不会推导出引用类型,因此推导出 m 的类型为 A*。这意味着程序将尝试复制doWarning 返回的引用所引用的指针。但是,doWarning 的返回值所引用的指针不再存在。试图复制不存在的对象是错误的,如果程序这样做了,它的行为是不确定的。