这种东西的新手,可能做错了什么,但是——
我有 3 位成员
std::unique_ptr<Gun> currentWeapon;
std::unique_ptr<Gun> weaponSlotOne;
std::unique_ptr<Gun> weaponSlotTwo;
Gun 是一个基类,具有其他派生类,如 Pistol
和 SMG
。
我正在做的是将weaponSlotOne
和weaponSlotTwo
设置为两把不同的枪,然后currentWeapon
设置为第一种武器。
weaponSlotOne.reset(new DevPistol());
weaponSlotTwo.reset(new AutoDevPistol());
currentWeapon = std::move(weaponSlotOne);
我有一个switchWeapons
方法,可以做到这一点:
void Player::switchWeapons() {
if(currentWeapon == weaponSlotOne) {
currentWeapon = std::move(weaponSlotTwo);
}
else {
currentWeapon = std::move(weaponSlotOne);
}
}
出于某种原因,这似乎摧毁/释放了两把枪。 我不太确定出了什么问题。
问题是,在对象上调用std::move
后,该对象处于不确定状态,除了销毁它或分配给它之外,您无法安全地对该对象执行任何操作。
在您的情况下,在执行currentWeapon = std::move(weaponSlotOne);
后,weaponSlotOne
是不确定的,因此当您测试currentWeapon == weaponSlotOne
时,您可能会得到任何结果。 可能,这将是假的(weaponSlotOne
将是空的),所以你只需将其复制到currentWeapon
,删除那里的任何内容(删除它)。
问题是,你想做什么? 如果你想要两种武器,并且想跟踪哪一种是最新的,那么这样做可能更有意义:
std::unique_ptr<Gun> *currentWeapon;
std::unique_ptr<Gun> weaponSlotOne;
std::unique_ptr<Gun> weaponSlotTwo;
weaponSlotOne.reset(new DevPistol());
weaponSlotTwo.reset(new AutoDevPistol());
currentWeapon = &weaponSlotOne;
void Player::switchWeapons() {
if(currentWeapon == &weaponSlotOne) {
currentWeapon = &weaponSlotTwo;
}
else {
currentWeapon = &weaponSlotOne;
}
}
或者更简单:
std::unique_ptr<Gun> weaponSlot[2];
int currentWeapon = 0;
void Player::switchWeapons() {
currentWeapon ^= 1;
}
通常,从对象移动后,移出对象处于有效但未指定的状态。 这意味着您只能在没有前提条件的移出对象上安全地调用那些函数。 例如,销毁通常没有先决条件。 通常,也不分配给对象。 通常,常量观察者也不会,例如与非移动值的相等比较。
对于 std::unique_ptr
,您可以安全地比较移自值。 但也要注意,unique_ptr
具有独特的所有权语义。 即两个非空unique_ptr
永远不应该相等,因为如果它们这样做,它们将拥有相同的指针,从而违反了unique_ptr
的基本租户。 但是,将unique_ptr
与nullptr
进行比较以了解它是否拥有非空指针通常是有意义的:
#include <cassert>
#include <memory>
int
main()
{
std::unique_ptr<int> p(new int(3));
auto p2 = std::move(p);
assert(p == nullptr); // perfectly legal & practical use of moved-from value
}
我怀疑您的代码的问题在于您错误地期望从unique_ptr
移动分配中复制语义:即分配的来源将保持不变。 但是,从我上面的代码片段中可以表明,移出的unique_ptr
将可靠地等于nullptr
。 根本没有其他方法可以在满足所有unique_ptr
规范的同时实现该操作。
万一有人能写到这篇文章。您可以在共享或唯一指针上使用 std::swap。
http://www.cplusplus.com/reference/memory/shared_ptr/swap/
编辑:
尽量避免使用以下代码:
weaponSlotOne.reset(new DevPistol());
它可能会导致内存泄漏。更好的是:
weaponSlotOne = std::make_unique<DevPistol>();