【问题标题】:STACK.peek function, having some trouble, C++STACK.peek 函数,有点麻烦,C++
【发布时间】:2023-03-23 10:20:02
【问题描述】:
CARD& STACK::peek()
{
    if(cards.size == 0)
    {
        CARD temp = CARD {-1, -1};
        return temp;
    }
    return cards.back();
}

这是我遇到问题的功能。

  • CARD 只是一个带有两个int 变量的struct,分别称为ranksuit

  • STACK 是一个管理std::vector<CARD>class,称为cards

该函数应该将reference 返回到堆栈顶部的卡片,或者如果vector 为空,则返回对虚拟卡片的引用。

首先,我收到一条警告,指出返回了对局部变量 temp 的引用。那有什么问题?这将如何影响功能?我该怎么办?

其次,我正在尝试将此函数与我创建的另一个名为cardToString的函数一起使用

char* cardToString(CARD& c);

它应该使用传递的CARD 中的ranksuit 变量来查找表中的字符串值,将两个字符串连接在一起,并返回一个指向新字符串的指针。

所以最终结果是这样的:

cout<<cardToString(deck.peek())<<"\n";

但这行代码将执行到cardToString 函数,然后由于某种原因停止。这让我很烦,因为它只是停止了,没有错误消息,而且看起来我没有任何问题。

有人可以帮帮我吗?

编辑:这里是cardToString 函数

char *cardToString(const CARD& c)
{
    if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
    {
        std::cout<<"returned null";
        return NULL;
    }

    char *buffer = new char[32];

    strcpy(buffer, RANKS[c.r]);
    strcat(buffer, " of ");
    return strcat(buffer, SUITS[c.s]);
}

我特别希望函数STACK.peek() 返回CARD 的地址,该地址已经存在于STACK 的顶部。这样做似乎比创建我要归还的卡的副本更有意义。

【问题讨论】:

  • 发布您的cardToString 函数可能有助于诊断问题。
  • 按值返回还是按引用返回还是按指针返回应该是语义的决定。从语义上讲,通过引用返回没有任何意义,因为其中一个可能的返回值,正如您所标记的那样,是临时的。
  • @ildjam 该类可能包含一个虚拟的CARD,它返回一个引用(类似于std::string::npos)。

标签: c++ class function struct tostring


【解决方案1】:

首先,我收到一条警告,指出返回了对局部变量 temp 的引用。那有什么问题?这将如何影响功能?我该怎么办?

一个局部变量,顾名思义,是它所属函数的局部变量,所以它在函数返回时被销毁;如果您尝试返回对它的引用,您将返回对在函数返回的那一刻将不复存在的东西的引用。

尽管在某些情况下这似乎仍然有效,但您很幸运,因为堆栈没有被覆盖,只需调用其他函数,您就会发现它会停止工作。

您有两个选择:首先,您可以通过值而不是引用返回CARD;但是,这样做的缺点是不允许调用者使用引用来修改 CARD 中存储的 vector(这可能是可取的,也可能不是可取的)。

另一种方法是在STACK 类中存储一个静态虚拟CARD 实例,它不会有这些生命周期问题,并且可以在vector 中没有元素时返回;但是,您应该找到一种“保护”其字段的方法,否则“愚蠢”的调用者可能会更改“单例”虚拟元素的值,从而破坏类的逻辑。一种可能性是在 class 中更改 CARD,这将封装其字段,如果它是虚拟元素,将拒绝对它们的写访问。

至于cardToString 函数,您可能对字符串做错了(我几乎可以肯定,在这种情况下,您也在尝试返回一个本地函数),但没有看到函数体很难说是什么。

顺便说一句,为了避免字符串出现许多问题,我建议您使用std::string 类而不是char *,它消除了通常@987654333 的大部分丑陋和低级内存管理@。

另外,我建议您更改 cardToString 以获取 const 引用,因为很可能不需要更改作为引用传递的对象,并且清楚地标记这一事实是一种很好的做法(如果您尝试更改此类引用,编译器会警告您)。


编辑 只要RANKSSUITS 数组正常,cardToString 函数应该可以正常工作。 但是,如果你像你写的那样使用那个函数,你就会泄漏内存,因为每次调用cardToString 你都会用new 分配一个永远不会用delete 释放的分配;因此,每次调用都会丢失 32 字节的内存。

如前所述,我的建议是使用std::string 并忘记这些问题;你的函数变得像这样简单:

std::string cardToString(const CARD& c)
{
    if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
        return "(invalid card)";

    return std::string(RANKS[c.r]) + " of " + SUITS[c.s];
}

而且您不再需要担心内存泄漏和内存分配。


对于引用/值的事情:如果调用者不需要使用引用来修改存储在vector中的对象,我强烈建议通过值传递它。性能损失可以忽略不计:两个ints 而不是一个指针,在大多数 32 位架构上意味着 8 对 4 字节,在大多数 64 位机器上意味着 8 字节对 8 字节(并且通过指针访问字段的成本也很小) .

这种微优化应该是您最不关心的问题。您的首要任务是编写正确工作代码,而您最不应该做的就是让微优化妨碍实现这一目标。

然后,如果您遇到性能问题,您将分析您的应用程序以找出瓶颈所在并优化这些关键点。

【讨论】:

  • 感谢有关内存泄漏的提示,请记住这一点。我会像你建议的那样使用一个字符串,但我正在努力学习如何做到这一点。
  • @Morshu:C++方式是std::string;将 char * 和完全手动的堆管理留给 C 程序员。
  • 好吧 escuuuse 我大声笑我只是在开玩笑谢谢你的帮助
【解决方案2】:

您不能返回对局部变量的引用,因为当函数返回时,局部变量不再存在。

您需要按值返回,而不是按引用(即CARD STACK::peek() { ... })。

【讨论】:

  • 另外cardToString 需要采用CARD const&amp; 而不是CARD&amp;,否则cardToString(deck.peek()) 将不起作用,因为deck.peek() 将返回一个右值。
猜你喜欢
  • 2011-04-29
  • 2011-12-23
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 2021-11-21
  • 1970-01-01
相关资源
最近更新 更多