如何将两个向量<unique_ptr <... >>设置为彼此相等?

zze*_*man 3 c++ vector unique-ptr visual-studio-2012

我正在使用Visual Studio 2012 C++,我想设置两个具有彼此相同的唯一指针的向量.

    using namespace std;
    vector<unique_ptr<Unit>> unitVector;
    vector<unique_ptr<Unit>> nonDeadUnits;

    .... (stuff added to unitVector) ....

    for (auto unit = unitVector.begin(); unit != unitVector.end(); ++unit) {
            if ((*unit)->health > 0) {
                    nonDeadUnits.push_back(*unit);
            }
    }

    unitVector.clear();
    unitVector = nonDeadUnits; // error here (see below error code)
Run Code Online (Sandbox Code Playgroud)

我想删除所有生命值小于0的单位,但是如果我尝试直接从向量中删除它们,我会尝试访问我不应该访问的内存,从而终止程序.这就是为什么我选择这样做的原因.唯一的问题是unique_ptr不允许我想要的复制类型.这是错误:

    error C2248: 'std::unique_ptr<_Ty>::operator =' : cannot access private member declared in class 'std::unique_ptr<_Ty>' c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility 2089
Run Code Online (Sandbox Code Playgroud)

我想有unique_ptr,因为向量在稍后的for循环中调用子类方法,它有助于覆盖.那么如何将矢量设置为彼此相等或者有更好的方法呢?

Quu*_*one 8

一般的想法是使用std::remove_if交换元素unitsVector,然后一旦所有死单位都在向量的末尾,你只需将它们切掉.

#include <memory>
#include <vector>

struct Unit {
    int health;
};

// The non-working version.
//
// void remove_dead_units(std::vector<std::unique_ptr<Unit>> &unitVector)
// {
//     std::vector<std::unique_ptr<Unit>> nonDeadUnits;
//     for (auto unit : unitVector)
//         if (unit->health > 0)
//             nonDeadUnits.push_back(unit);
//     unitVector = nonDeadUnits;
// }

void remove_dead_units(std::vector<std::unique_ptr<Unit>> &unitVector)
{
    auto isDead = [](const std::unique_ptr<Unit> &u) -> bool { return (u->health <= 0); };
    auto newEnd = std::remove_if(unitVector.begin(), unitVector.end(), isDead);
    unitVector.erase(newEnd, unitVector.end());
}
Run Code Online (Sandbox Code Playgroud)

我确信还有其他方法可以做到这一点,更接近于你所尝试的内容(编辑:实际上KerrekSB刚刚发布了一个,只使用了一个std::move和一个swap); 但我认为"shuffle and chop"方法更现代--C++ ish.


Ker*_* SB 5

也许以下逻辑会更简单:

vector<unique_ptr<Unit>> unitVector = /* ... */;
vector<unique_ptr<Unit>> nonDeadUnits;

for (auto & p : unitvector)
{
    if (p->health > 0) { nonDeadUnits.push_back(std::move(p)); }
}

unitVector.swap(nonDeadUnits);
Run Code Online (Sandbox Code Playgroud)

否则,标准的删除 - 删除习惯可能更多是主流:

unitVector.erase(remove_if(unitVector.begin(), unitVector.end(),
                           [](unique_ptr<Unit> const & p) -> bool { return p->health <= 0; }),
                 unitVector.end());
Run Code Online (Sandbox Code Playgroud)