C++ 交换unique_ptr



这种东西的新手,可能做错了什么,但是——

我有 3 位成员

std::unique_ptr<Gun> currentWeapon;
std::unique_ptr<Gun> weaponSlotOne;
std::unique_ptr<Gun> weaponSlotTwo;

Gun 是一个基类,具有其他派生类,如 PistolSMG

我正在做的是将weaponSlotOneweaponSlotTwo设置为两把不同的枪,然后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_ptrnullptr进行比较以了解它是否拥有非空指针通常是有意义的:

#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>();

相关内容

  • 没有找到相关文章

最新更新