函数从收缩向量返回字符。向量为空时返回什么?

时间:2016-12-06 08:57:11

标签: c++ vector

我正在编写一个棋盘游戏,其中必须从包中取出随机碎片(想象从袋中拉出Scrabble碎片)。

我使用以下函数从向量(代表包)返回随机字符(代表片段):

vector<char> pieces = {'A','B','C','D','E','F'};

char pullPiece() {
    int randomIndex = rand() % pieces.size();
    char c = pieces[randomIndex]; // Get the piece
    pieces.erase(pieces.begin() + randomIndex); // Remove the piece
    return c;
}

检索到char后,它将从向量中删除。然后该函数返回检索到的char。

当向量pullPiece()删除了所有元素且为空时,处理pieces调用的最佳方法是什么?

我唯一能想到的就是抛出一个异常,但是因为每次我的游戏都会发生这种情况,所以看起来并不是一个例外。我还考虑在调用pullPiece()之前检查向量的大小,但我觉得我应该将此功能编程到pullPiece()函数本身。

5 个答案:

答案 0 :(得分:3)

一种非常简单的方法是为空案例返回\0

从向量中返回迭代器而不是char可能值得重构。然后,您可以安全地返回pieces.end()。这是C ++标准库容器实现它的方式。请注意,您可以测试pieces.end()的迭代器,但不要尝试取消引用迭代器或增加迭代器。 (只要容器不为空,就可以将迭代器设置为pieces.end()。)

类似C的方法是重构函数以返回int,并返回EOF作为特殊值。 (参见isupperislower等。)

答案 1 :(得分:2)

在新的std(c ++ 17)中有一些叫做std :: optional的东西。意味着返回值可能存在,那么它只是你的char,否则会出现&#34; invalidbit&#34;可以检查。 boost也有一个可选类型。

您可以返回0表示无效或负数。

其他解决方案,比如给出一个有效标志作为参考并将其设置为有效,但我认为并不是那么好。

答案 2 :(得分:2)

你有一个函数需要返回一个char,或者没有返回char的信息。有不同的方式:

干净,笨拙和低效:如果没有要返回的字符,则抛出异常。

清理,有点工作:有一个函数可以告诉你在检索char之前是否有一个必须被调用的char。如果没有可用的char是一个必须修复并终止你的应用程序的错误。

不干净但效率高:定义一个char值以指示“没有数据可用”,例如'\ 0'。在某些情况下,它比其他情况更好。它可以在这里工作,因为只有一小部分char值可以返回。当您返回指向对象的指针或空指针时,它通常很有效。如果任何返回值有效,它根本不起作用。

干净,高效,但不是在C ++中:返回一个可选值。这就是为什么选择。 (我被告知可选项正在以新标准提供;使用它们。这就是为什么选项制作的)。

干净,效率很高,略显笨拙:返回一个bool值表示呼叫成功。传递char *或char&amp;到它存放结果的函数(char&amp;具有不能传递空指针的优点; char *的优点是在源代码中很清楚char值将被修改)。

干净,效率很高,略显笨拙:返回一个带有char值的结构,以及一个指示char值有效的bool(这与返回一个可选值几乎相同)。

我个人更喜欢以支持它的语言返回可选值。否则我更喜欢返回bool表示成功,并通过指针返回值,因为它是始终工作的方法;任何价值。

答案 3 :(得分:0)

在调用函数之前,您可以检查向量是否为空。

http://www.cplusplus.com/reference/vector/vector/empty/

或者,在函数内部,检查向量是否为空,只返回\ 0;

答案 4 :(得分:0)

自己选择:

char pullPiece() noexcept; // 1) precondition: Pieces must be available.
char pullPiece();          // 2) Throws, if no piece is available.
std::optional<char> pullPiece() noexcept; // 3)

在功能界面中需要考虑不同的方面:

  • 这很简单吗?
  • 是否可以实现高效的实施?
  • 意图是否明确? (我可以做错什么吗?)

1)显然,当要求客户端满足前提条件时,函数本身不一定要检查它。 (即使在调试版本中,强烈建议使用assert()。)因此,接口1)允许最有效的实现。

2)这是最简单的界面。但是,客户端程序员必须阅读注释才能知道如何处理空案例。那么,事情会出错吗?是的,它可以。这可怕吗?不必要。但我会避免将异常作为正常控制流程的一部分。

3)第三个界面清晰。什么都不会出错。它不再那么简单,但程序员不需要检查角落案例的文档。从功能签名中可以清楚地看到。如果检查空虚的开销不是太大的负担,那么我会选择这个解决方案。

但请注意,std::optional<T> is only available by the C++ standard starting with C++17。有些编译器已implement it in the namespace std::experimental,e。 G。 gcc 4.9或clang 3.4都在C ++ 14模式下。一种替代方案,即使对于较旧的编译器也可以使用boost::optional<T>