我正在编写一个棋盘游戏,其中必须从包中取出随机碎片(想象从袋中拉出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()
函数本身。
答案 0 :(得分:3)
一种非常简单的方法是为空案例返回\0
。
从向量中返回迭代器而不是char
可能值得重构。然后,您可以安全地返回pieces.end()
。这是C ++标准库容器实现它的方式。请注意,您可以测试pieces.end()
的迭代器,但不要尝试取消引用迭代器或增加迭代器。 (只要容器不为空,就可以将迭代器设置为pieces.end()
。)
类似C的方法是重构函数以返回int
,并返回EOF
作为特殊值。 (参见isupper
,islower
等。)
答案 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>
。