2011-01-25 80 views
2

我有一个堆栈容器类,我想创建各种类型的堆栈实例。所以我这样做:C++模板问题:转换为空

template <typename T> 
class MyStack 
{ 
. 
. 
    T Pop() 
    { 
     if(!IsEmpty()) 
     { 
     return data[top--]; 
     } 
     else 
     { 
     return NULL; // I got error here 
     } 
. 
. 
} 

当我尝试使用堆栈是这样的:

MyStack<GraphNode> blacks; 
GraphNode t = blacks.Pop(); 

我得到这个错误:

conversion from ‘int’ to non-scalar type ‘GraphNode’ requested 

但是当我使用指针类型一样Stack<GraphNode*>有没问题。我知道NULL0,我明白为什么会发生错误...什么是优雅的方式来告诉程序,没有数据要返回而不更改代码?我应该添加类似隐式类型转换操作符类吗?怎么样?

注:我不使用STL

+0

可能重复的[如何从模板类中的方法返回NULL](http://stackoverflow.com/questions/1392869/how-to-return-null-from-a-method-in-a-模板级) – Suma 2011-01-25 20:43:17

+0

+1重复,但很难保证downvote。这是一个很好的问题。 – Skurmedel 2011-01-25 20:45:04

+0

downvote是尝试一些设计不好的东西,应该完全避免 - “不用更改代码?”。没有必要被迷恋 - downvote只是一个downvote,一个个人的观点,它不是“从地球表面擦拭他”。 – Suma 2011-01-25 20:47:58

回答

6

通过按值返回T,您的功能合同是您返回一个值。这两种方法是更改​​函数的合同(例如,改为返回T*),或者抛出异常而无法返回。

就我个人而言,我认为在这种情况下抛出异常是可以接受和适当的。返回一个指针,或者谈论覆盖并返回一个布尔成功值的引用都不是那么干净的解决方案。

特别是如果您提供公开的IsEmpty()方法,没有理由选择不太干净的解决方案。不想处理异常的客户端可以使用IsEmpty来避免接收到等同于断言的异常。

3

的规范弹出函数返回void,这个确切原因。另外,你没有调用Bad的数据析构函数[top]。

如有疑问,请检查STL

5

STL std::stack将此功能拆分为top(),它返回最后一个元素的引用,pop()。如果您使用其中的任何一种,并且堆栈已经为空(即如果empty() == true),则行为是简单的未定义的。这听起来不是一个坏的方法。

3

如果您还没有阅读GoTW #8,现在应该这样做。它完全致力于手头的问题 - 如何设计堆栈。其最基本的一点是,您目前使用的设计pop不能将设为异常安全。

它给手头上的问题(不一定是一个好......)答案是返回一个缺省构造■如果堆栈是空的:

T Pop() 
{ 
    if(!IsEmpty()) 
    { 
    return data[top--]; 
    } 
    else 
    { 
    return T(); // No more error 
    } 
} 

这样做的问题是,在大多数的情况下,试图弹出一个空堆栈表明一个逻辑错误,并且不应该被允许继续进行。您可以在使用assert或抛出异常之间进行无休止的辩论,但很少有可以返回的值,这非常有用(可能的例外是在处理F.P.数字时返回NaN)。