为什么将指针转换为引用在我的访问器 (getter) 中不起作用?

Why converting a pointer into a reference doesn't work in my accessor (getter)?

本文关键字:getter 不起作用 访问 我的 指针 转换 引用 为什么      更新时间:2023-10-16

我最近学会了如何使用这个技巧将指针转换为引用。但是当我在访问器中执行此操作时,它似乎创建了一个未定义的行为,我不明白为什么。

我为什么要这样做

我有一个拥有class Walker实例的class WalkerOwner。这个Walker实例在代码的其他地方是需要的,所以我提供了一个访问器(getter)到类WalkerOwner,它提供了一个参考。

class WalkerOwner
{
public:
...
Walker& getWalker() {return m_ownedWalker;} ;
private:
Walker m_ownedWalker;
};

后来,我意识到出于某种原因,WalkerOwner实际上应该在内部管理指向步行者的指针。由于我不想重构代码的其余部分,将每个引用都更改为指针,因此我尝试将指针转换为 getter 中的引用。

显示问题的代码

#include <iostream>
#include <string>
using std::string;
class Walker
{
public:
Walker() : m_travelledDistance(5) {};
~Walker(){};
void swank() { std::cout << "I have walked " << distanceAsString() << "! How good I am!" <<  std::endl; };
private:
// Calling this function makes the result even more impressive
string distanceAsString() { return std::to_string(m_travelledDistance) + " meters" ; };
int m_travelledDistance;
};
class WalkerOwner
{
public:
WalkerOwner() {m_ownedWalker = new Walker; } ;
~WalkerOwner() { delete m_ownedWalker;};
// I know I should throw an exception if the pointer is not valid.
Walker& getWalker() {return Walker(*m_ownedWalker);} ; //conversion from pointer into reference
private:
Walker* m_ownedWalker;
};

int main(int argc, char *argv[])
{
// -------
// Case 1
// If "main" owns John the walker, everything seems fine.
// -------
Walker* ptrToJohn = new Walker ;
Walker& john = Walker(*ptrToJohn); //conversion from pointer into reference
john.swank();
delete ptrToJohn ;
// -------
// Case 2
// If someone else owns Jack the walker, a disaster occurs.
// -------
WalkerOwner walkerOwner ;
Walker& jack = walkerOwner.getWalker() ;
// (When I put a breakpoint here, my Integrated Devlopment 
// Environnment says that walker.m_travelledDistance = 5)
jack.swank(); 
std::cin.get(); // Press enter to close
return EXIT_SUCCESS;
}

当我运行此代码时,我得到以下输出:

我走了5米!我多好啊!

我走了-858993460米!我多好啊!

有趣的是,断点显示 jack 在调用函数 "swank()" 之前处于预期状态。(哼...也许哗啦让他失去了理智!

无论如何,如果有人能向我解释这种行为,并可以判断是否有可能制作一个执行此转换的安全访问器,我将非常高兴。

通过编写return Walker(*m_ownedWalker);,您不会从*m_ownedWalker"转换"为完整的Walker:您正在使用当前Walker作为源创建一个

简单return *m_ownedWalker;

正如@user2079303指出的那样:因为你要返回一个新的Walker,然后不把它保存在任何地方(保存引用与保存实际值不同),它会立即被销毁。然后你拒绝了(现在已经死了,无论如何未初始化的)副本——难怪垃圾被打印出来了!