2011-04-05 99 views
0
CARD& STACK::peek() 
{ 
    if(cards.size == 0) 
    { 
     CARD temp = CARD {-1, -1}; 
     return temp; 
    } 
    return cards.back(); 
} 

这是我遇到麻烦的功能。STACK.peek功能,遇到一些麻烦,C++

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

  • STACK是管理std::vector<CARD>class,即cards

功能应该一个reference返回到卡上的堆栈的顶部,或者所述参考返回到虚拟卡若vector是空的。

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

其次,我想使用此功能与其他功能我创建了名为cardToString

char* cardToString(CARD& c); 

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

所以最终的结果是这样的:

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()返回已经存在的STACK顶部CARD的地址。这样做似乎更有意义,而不是创建我想要返回的卡的副本。

+0

发布'cardToString'函数可能有助于诊断问题。 – uesp 2011-04-05 23:59:36

+1

按指针返回的值与参考值的比较应该是*语义*的决定。在语义上,通过引用返回没有任何意义,因为可能的返回值之一是,如您标记的那样,是暂时的。 – ildjarn 2011-04-06 00:15:01

+0

@ildjam该类可能包含一个虚拟的'CARD',它返回一个引用(类似于'std :: string :: npos')。 – user470379 2011-04-06 00:58:18

回答

1

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

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

+0

'cardToString'需要一个'CARD const&'而不是'CARD&',否则'cardToString(deck.peek())'将不起作用,因为'deck.peek()'将返回一个右值。 – ildjarn 2011-04-05 23:59:15

3

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

正如其名称所暗示的,局部变量对于它所属的函数是局部的,所以它在函数返回时被销毁;如果您尝试返回对其的引用,那么您将返回对该函数返回时不再存在的内容的引用。

虽然在某些情况下这看起来可能工作,但你只是幸运因为堆栈没有被覆盖,只是调用其他函数,你会发现它会停止工作。

您有两种选择:首先,您可以通过值而不是引用返回CARD;然而,这具有不允许呼叫者使用该参考来修改存储在vector中的该参考(这可能或可能不是期望的)的缺点。

另一种方法是具有存储在STACK类的静态虚拟CARD情况下,将不会有这些生命周期问题,可以返回时,你不必在vector元素;然而,你应该找到一种方法来“保护”它的领域,否则一个“愚蠢的”调用者可能会改变你的“单身”虚拟元素的值,从而搞砸了这个类的逻辑。一种可能性是CARDclass中将封装其字段,并且如果它是虚拟元素将拒绝对它们的写入访问。

至于cardToString函数,你可能在字符串上做错了什么(而且我几乎可以肯定你也试图在本例中返回一个本地),但是没有看到它的函数体很难说什么。

顺便说一句,以避免许多问题串,我建议你使用,而不是char *std::string类,这需要最丑陋的和通常char *低级别的内存管理的路程。

此外,我建议你改变cardToString采取const参考,因为很可能它不需要改变作为参考传递的对象,并且清楚标记这个事实是很好的做法(编译器会警告你如果你试图改变这样的参考)。


编辑cardToString功能应该是做工精细,只要RANKSSUITS阵列都OK。 但是,如果您使用的是类似于您写的功能,则表明您正在泄漏内存,因为对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]; 
} 

而且你不必担心内存泄漏和内存分配了。


对于参考/值的事情:如果调用者不需要使用参考修改存储在矢量对象,我强烈建议按值传递。性能影响可以忽略不计:两个int而不是一个指针意味着在大多数32位体系结构中8个字节与4个字节,而在大多数64位机器上8个字节与8个字节(并且通过指针访问字段的代价很小)。

这种微型优化应该是您最后关心的问题。你的首要任务是编写正确的工作的代码,你应该做的最后一件事是让微优化克服这个目的。

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

+0

感谢关于内存泄漏的提示,请牢记这一点。我只会使用你建议的字符串,但我试图学习如何做很长的路。 – Morshu 2011-04-06 00:30:06

+0

@Morshu:C++的方式是'std :: string';将'char *'和完全手动的堆管理留给C程序员。 – 2011-04-06 00:32:12

+0

好escuuuse我大声笑即时通讯只是开玩笑感谢您的帮助,虽然 – Morshu 2011-04-06 01:18:39