c++ - 使用删除-删除范例将元素从一个 vector move 到另一个 vector

标签 c++ c++11 vector move

This question清楚地阐明了如何从一个 std::vector move 内容给另一个。简而言之,有一个 std::move物理 move 内存所需的调用,同时还有一个 std::erase需要调用以调整原始 vector 的大小以考虑删除的元素。

使用 erase-remove paradigm 执行此操作是否有问题?就像人们在迭代它的同时从 vector 中删除一样(比如 here )?

例如,像这样:

// Vector with values [0, 1, ..., 19]
std::vector<int> myOldVec;
for (int i = 0; i < 20; i++) { myOldVec.push_back(i); }

// New vector to move into
std::vector<int> myNewVec;

// Move from myOldVec to myNewVec if value is less than 5
myOldVec.erase(
    std::remove_if(
        myOldVec.begin(),
        myOldVec.end(),
        [&](const int x)
        {
            if (x < 5)
            {
                myNewVec.push_back(x);
                return true;
            }
            return false;
        }
    ),
    myOldVec.end()
);

预期的输出是

myOldVec --> [5, 6, ..., 19]
myNewVec --> [0, 1, 2, 3, 4]

当我运行这段代码时,它可以在我的测试仪中运行。但是,在处理对象而不是 int 时s 我担心我实际上并没有 move 任何东西,而只是引用;例如,当使用 std::vector<MyObj> 执行上述操作时相反(使用适当的 lambda 测试)。

这真的是在表演 Action ,还是我担心我只是在分享一个引用?

最佳答案

我认为通常这些算法的要点是,您正在通过应用函数来实现您想要实现的目标。一旦函数有副作用,看起来最终结果可能会产生误导,做一个 for 循环可能会更好。

也就是说,请记住 C++ 不是 Java。 vector<Foo>必须存储 Foo 的,它只是不能存储引用。但是,你的整个想法还是有问题。

myNewVec.push_back(x);

您代码中的这一行将推送 x拷贝进入你的新载体。因为它是拷贝,所以您不必担心共享引用。现在,对于整数,复制和 move 是相同的。但是对于复杂的对象(比如 vector ), move 可能比复制快得多。无论如何,唯一的载体就是摆脱 x ,所以我们肯定要搬家。所以理想情况下,我们将该行更改为:

myNewVec.push_back(std::move(x));

但是,从一个对象 move 显然会改变它,并且要求它不是常量。 remove_if的要求但是要求传递的函数对象是一个谓词。这反过来意味着:

The function object pred shall not apply any non-constant function through the dereferenced iterator.

http://en.cppreference.com/w/cpp/concept/Predicate

换句话说,您的函数必须接受取消引用迭代器的结果,但不应该改变它。因为它不应该改变它,所以您永远不能从原始对象 move ,而必须复制它。因此,我认为对于非平凡类型,没有任何一致、有效的实现这一想法。

这是一个合理的实现:

template <class T, class F>
void transfer_if_not(std::vector<T>& old, std::vector<T>& new, F pred)
{
    auto part = std::partition(old.begin(), old.end(), pred);
    std::move(part, old.end(), std::back_inserter(new));
    old.erase(part);
}

这至少不应该复制任何元素。它基本上会分离出原始 vector 中要保留和保留的元素。然后有效地搬走那些离开的人。然后简单地调整数组的大小。正如评论中指出的那样,与最佳版本相比,这可能涉及额外的操作,但我的感觉是最佳版本的代码编写起来并不简单,并且可能涉及权衡(如更多状态),因此它可能不是纯粹的胜利.

请注意,我的算法专门接受 vector 而不是迭代器,因为对于其他容器(比如链表),此实现远非最佳。

关于c++ - 使用删除-删除范例将元素从一个 vector move 到另一个 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42589008/

相关文章:

c++ - 编译器提示 make_shared() 期望左值

c++ - 如何终止 C++11 中的线程?

c++ - 我可以获得正式而非实际模板参数的字符串表示形式吗?

vector - 嵌套数据结构的 Rust 可变性

c++ - 从 vector 中的父基转换的模板化子 T 生成的虚假字符

c++ - 从二维数组中检索数组元素

c++ - CreateProcess() 错误

php - swig 和 libcurl 在一起

algorithm - "cut and paste"std::vector 的最后 k 个元素有效吗?

c++ - 如何在 C++ 中检查 vector 中的哪些对象