如何 push_back 一个 "unique_ptr<Base>&" 到 "vector<unique_ptr<Derived>>"

How to push_back a "unique_ptr<Base>&" to "vector<unique_ptr<Derived>>"

我需要通过一些条件检查在 2 vector<unique_ptr> 之间移动元素。移动后,我将忽略from-vector(将所有权转移到to-vector)。

案例 1:从 vector<unique_ptr<Derived>> fromDeriveds 移动到 vector<unique_ptr<Base>> toBases

vector<unique_ptr<Derived>> fromDeriveds;
vector<unique_ptr<Base>> toBases;
   
for (unique_ptr<Derived> &derived: fromDeriveds)
{
    if (derived->prop == 1)
    {
        toBases.push_back(move(derived));
    }
}

这个案例不错

情况 2:从 vector<unique_ptr<Base>> fromBases 移动到 vector<unique_ptr<Derived>> toDeriveds

vector<unique_ptr<Base>> fromBases;
vector<unique_ptr<Derived>> toDeriveds;
   
for (unique_ptr<Base> &base: fromBases)
{
    Derived *derived = dynamic_cast<Derived *>(base.get());
    if (derived && derived->prop == 1)
    {
        toDeriveds.push_back(move(base));
    }
}

编译失败,出现以下错误:

main.cpp:44:44: error: no matching function for call to ‘std::vector<std::unique_ptr<Derived> >::push_back(std::remove_reference<std::unique_ptr<Base>&>::type)’
             toDeriveds.push_back(move(base));
                                            ^

虽然我可以通过下面的方式来完成,但它是复制而不是移动:

vector<unique_ptr<Base>> fromBases;
vector<unique_ptr<Derived>> toDeriveds;
   
for (unique_ptr<Base> &base: fromBases)
{
    Derived *derived = dynamic_cast<Derived *>(base.get());
    if (derived && derived->prop == 1)
    {
        toDeriveds.push_back(make_unique<Derived>(*derived));
    }
}

有没有更好的方法来实现目标?

您可以迭代 fromBase 列表并进行检查,如果满足该要求,那么您可以简单地 release 指针 - 它会在不调用析构函数的情况下放弃基指针。只要确保删除已释放的空指针,以防您需要再次使用 fromBase 向量。

WANDBOX LINK

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

using namespace std;

class Base{ public: virtual ~Base() = default; };
class Derived: public Base {};


int main() {
    vector<unique_ptr<Base>> fromBase;
    vector<unique_ptr<Derived>> toDerived;
    
    fromBase.emplace_back(make_unique<Base>());
    fromBase.emplace_back(make_unique<Base>());
    fromBase.emplace_back(make_unique<Derived>());
    
    for(auto& p: fromBase) {
        Derived* d = dynamic_cast<Derived *>(p.get());
        // make other checks here
        if(d != nullptr) {
            toDerived.emplace_back(d);
            p.release();
        }
    }

    // make sure to remove released pointers
    fromBase.erase(remove_if(fromBase.begin(), fromBase.end(), [](const auto& p) { return !p; }), fromBase.end());
    
    cout << fromBase.size() << " " << toDerived.size() << endl;
}