C++ 纸牌游戏中的移动语义

C++ 纸牌游戏中的移动语义,c++,C++,我正在用C++编写纸牌后端。如果我不必怀疑某个东西是被复制还是被移动,生活会变得更容易,但是C++在这种情况下有什么意义呢?我只使用Python:d Anyhoo-我有一个Card对象,它遵守5的规则(它有一个构造函数、复制构造函数、复制赋值操作符、移动构造函数、移动赋值操作符)。我有不同的卡片分类 到目前为止,我一直在使用std::vector cards存储卡,每次我需要将卡从一个堆栈移动到另一个堆栈时,我都会: auto last_card = cards.back(); // Get t

我正在用
C++
编写纸牌后端。如果我不必怀疑某个东西是被复制还是被移动,生活会变得更容易,但是
C++
在这种情况下有什么意义呢?我只使用Python:d

Anyhoo-我有一个Card对象,它遵守5的规则(它有一个构造函数、复制构造函数、复制赋值操作符、移动构造函数、移动赋值操作符)。我有不同的卡片分类

到目前为止,我一直在使用
std::vector 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
,这样我所做的只是复制/移动指针,而不是真正的对象吗

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

谢谢


编辑:为了澄清,
卡片
对象确实很简单。只是一套西装,价值和颜色(由西装推断)。所有3个都是枚举,还有其他辅助功能,用于翻转卡片、检查卡片是正面朝上还是正面朝下等。

这很好,除了几个细节:

return std::move(last_card); // Move the card and return it.
这是一个常见的误解,认为你需要或应该这样做。在
return
语句中,右边的东西自动是一个xvalue,因此它已经处于可移动状态。从这个意义上说,
std::move
是多余的

但比这更糟糕的是,通过编写
std::move
,编译器甚至更难完全省略移动-只需编写
return last_card
,您就可以得到您首先想要的移动,或者更好地得到一个总返回值省略,从而避免整个shebang

现在,您有一份来自
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;

但是,这一切都是基于你对
卡的描述而进行的模拟,这非常简单,而且不会从移动中获得任何好处。坦率地说,你可以复制一下,得到同样的结果。尽管如此,为将来变得更加复杂做好准备还是很好的。当然,这里没有什么东西需要独特的

这很好,除了几个细节:

return std::move(last_card); // Move the card and return it.
这是一个常见的误解,认为你需要或应该这样做。在
return
语句中,右边的东西自动是一个xvalue,因此它已经处于可移动状态。从这个意义上说,
std::move
是多余的

但比这更糟糕的是,通过编写
std::move
,编译器甚至更难完全省略移动-只需编写
return last_card
,您就可以得到您首先想要的移动,或者更好地得到一个总返回值省略,从而避免整个shebang

现在,您有一份来自
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;

但是,这一切都是基于你对
卡的描述而进行的模拟,这非常简单,而且不会从移动中获得任何好处。坦率地说,你可以复制一下,得到同样的结果。尽管如此,为将来变得更加复杂做好准备还是很好的。当然,这里没有任何东西需要一张
唯一的\u ptr

你能告诉我为什么你使用
移动
而不是只返回
最后一张卡
?一些C++的最佳实践我不知道?没有看到你的代码>卡< /Cord>类,这是不可能说的。但我(表面上)的反应是这太复杂了;一张卡片只是几个值(suit和rank),特殊功能的默认版本可以正常工作。不必担心移动和复制,它们是一样的。通过移动返回通常是错误的。它可以抑制复制省略(这比移动更好)。是否
包装任何资源(例如内存)?
返回最后一张卡是一个更好的解决方案。具有自动存储持续时间的局部变量在
return
语句中被视为右值。您可能还需要
auto last_card=std::move(cards.back()),否则复制最后一个元素,然后立即销毁。您能告诉我为什么使用
move
,而不只是返回
last_card
?一些C++的最佳实践我不知道?没有看到你的代码>卡< /Cord>类,这是不可能说的。但我(表面上)的反应是这太复杂了;一张卡片只是几个值(suit和rank),特殊功能的默认版本可以正常工作。不必担心移动和复制,它们是一样的。通过移动返回通常是错误的。它可以抑制复制省略(这比移动要好)。
是否包装任何资源(例如mem)