在单人纸牌游戏中移动语义

时间:2018-12-28 13:53:16

标签: c++

我正在C++中写一个纸牌后端。如果我不必怀疑是否要复制或移动某些内容,生活会更轻松,但是在这种情况下C++的意义是什么?我只用Python:D。

Anyhoo-我有一个Card对象,它遵循5的规则(它有一个构造函数,Copy构造函数,Copy Assignment运算符,Move构造函数,Move Assignment运算符)。我为各种不同的卡牌设置了单独的课程。

到目前为止,我一直在使用std::vector<Card> cards来存储卡,每次需要将卡从一叠移动到另一叠时,我都会这样做:

auto last_card = cards.back(); // Get the last element in the collection.
cards.pop_back(); // Remove the last element.
return std::move(last_card); // Move the card and return it.

我的问题是-这是正确的方法吗?我是否应该改为使用std::vector<std::unique_ptr>,以便我所做的只是复制/移动指针而不是实际对象?

我正在寻找最佳实践,因为我还是C ++的新手。任何提示/建议将不胜感激。

谢谢!

编辑:为澄清起见,Card对象确实非常简单。只是一套西装,价值和颜色(由西装推断)。这3个都是枚举,并且还有其他辅助功能可用于翻转卡,检查卡面朝上还是朝下等。

1 个答案:

答案 0 :(得分:4)

这很好,除了几个细节:

return std::move(last_card); // Move the card and return it.

这是一个常见的误解,您需要或应该这样做。在return语句中,右边的东西自动是 xvalue ,因此它已经处于可移动状态。从这个意义上讲,std::move在这里是多余的。

但是,这要比那差一点,因为编写std::move会使编译器更加难以完全忽略甚至移动—仅编写return last_card就可以得到想要的移动首先,甚至更好的是总避免了整个“爆炸”的总返回值选择。

现在,您当前有一份来自cards.back()的副本; cards.back()表达式不是那里的右值,因为它是对其他地方存在的东西的引用,基本上是左值!所以您可能想这样做:

auto last_card = std::move(cards.back());

我还想提醒您注意“移开卡片并归还卡片”的注意事项:请记住,std::move不会移动任何东西,它只是为您提供了一个指向事物的右值表达式。如果发生移动,它将在返回操作中,而不是在返回操作中。

最后,我的建议:

// Extract the last element in the collection
auto last_card = std::move(cards.back());

// Remove the now-dead last element
cards.pop_back();

// Return the new card (will automatically be moved if elision doesn't occur)
return last_card;

但是,根据您对Card的描述,这完全是没有根据的,这很简单,也没有从搬家中获得任何好处。坦白说,您可以将其复制并获得相同的结果。尽管如此,为将来变得更加复杂做准备还是很高兴的。当然,这里没有任何人为unique_ptr尖叫。