c ++交换unique_ptr' s

时间:2014-11-25 01:48:54

标签: c++ smart-pointers 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);
    }
}

由于某种原因,它似乎会破坏/解除分配两种枪支。我不太确定出了什么问题。

3 个答案:

答案 0 :(得分:1)

问题是在对象上调用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;
}

答案 1 :(得分:1)

通常,在从对象移动后,移动的对象处于有效但未指定的状态。这意味着您只能在没有前提条件的移动对象上安全地调用这些函数。例如,破坏通常没有先决条件。通常也没有分配给对象。并且通常情况下,const观察者都没有例如与非移动值进行相等比较。

对于std::unique_ptr,您可以安全地比较移动值。但另请注意,unique_ptr具有唯一所有权语义。即两个非null unique_ptr s永远不应该相等,因为如果它们相同,它们将拥有相同的指针,因此违反了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规范的情况下,没有其他方法可以实现该操作。

答案 2 :(得分:0)

以防万一有人登上此职位。您可以在共享或唯一指针上使用std :: swap。

http://www.cplusplus.com/reference/memory/shared_ptr/swap/

编辑:
尽量避免这样的代码:

weaponSlotOne.reset(new DevPistol());

它可能导致内存泄漏。更好的是:

weaponSlotOne = std::make_unique<DevPistol>();