【问题标题】:C++ possible to use move sematics to move data from one vector to anotherC++ 可以使用移动语义将数据从一个向量移动到另一个向量
【发布时间】:2019-08-13 14:47:17
【问题描述】:

下面的代码将数据从一个向量复制到另一个向量。如果向量很大,那么我想这很昂贵。是否可以在这里使用移动语义将数据从一个向量复制到另一个向量?

std::vector<double> newData(Shape.Size(), 0);
std::vector<double> oldData = a->getData();
std::copy(oldData.begin(), oldData.end(), newData.begin());

【问题讨论】:

  • 可以将数据从一个向量移动到另一个向量;结果当然是源向量将仅包含已移动的数据,即其中的数据将被更改。你的场景可以吗?
  • @Angew 你的意思是源向量将包含garbage 数据,因为原始数据已被移动?
  • move sematics to copy data from one vector to another 移动的重点是避免复制...
  • @Borgleader 确认并更新感谢
  • 在这个例子中,复制和移动没有区别,因为向量包含不受移动影响的类型。

标签: c++ c++11 vector move-semantics


【解决方案1】:

您可以使用算法std::move 代替std::copy

std::move(oldData.begin(), oldData.end(), newData.begin());

它仍然会逐个元素地传输元素,但会移动它们。不要忘记预先分配具有正确大小的向量以避免移动元素过多。

【讨论】:

  • 我知道std::move 会尽可能移动元素,否则会复制。 std::copy 将始终复制。在这种情况下std::move 真的会移动它们吗?
  • @blacksheep 在doubles 的情况下,移动与复制没有什么不同。你可以说doubles 总是被复制的。
  • @HolyBlackCat 这仅适用于双打(为什么?)它适用于哪些其他类型?谢谢
  • @blacksheep 实际移动(例如移动std::vectors)通常是从旧对象中提取资源(例如堆分配的块)以将它们用于新对象。对于std::vector,旧对象的堆分配块用于新对象(移动后,旧对象不再拥有该块)。 doubles 不拥有任何资源,它们只是字节序列。
  • @blacksheep 移动只有在处理指针时才有意义。如果你有类似双的东西,你必须制作一个副本,因为没有什么可以移动的。如果您有类似 std::vector 的东西,它有一个指向某个内存的指针,那么当您移动时,您所做的就是将指针复制到新向量中,以便您移动资源的所有权。
【解决方案2】:

是的,您可以使用 std::move_iterator

std::copy(std::make_move_iterator(oldData.begin()), 
          std::make_move_iterator(oldData.end()), 
          newData.begin());

正如@tkausl 所说,这对于内置类型的vector 没有多大意义;最后在这种情况下执行复制。您可能想直接移动 vector,例如

std::vector<double> newData = std::move(oldData); // move construction

newData = std::move(oldData); // move assignment

【讨论】:

  • 这对于双打向量来说有点毫无意义。 OP 应该移动整个向量,而不是它的内容。
  • @songyuanyao 谢谢,我明白了——你怎么直接移动矢量?
  • @blacksheep 答案已修改。
【解决方案3】:

在提供的示例中移动或复制没有区别,因为向量中的值在移动期间不执行任何空间操作(它是双精度)。

这是一个合理的例子:

 using FooPtr = std::shared_ptr<Foo>;

 constexpr size_t n = 100;
 std::vector<FooPtr> data;
 data.reserve(n);
 std::generate_n(std::back_inserter(data), n, FooFactory);

 std::vector<FooPtr> dst;
 dst.reserve(n);
 std::move(std::begin(data), std::end(data), std::back_inserter(dst));

注意

 dst = std::move(data);

会更快,因为数据缓冲区将被重新分配给另一个向量。

https://wandbox.org/permlink/pJnmrWYe40hLRYNE

其他答案使用make_move_iterator。如果与其他算法一起使用,这是实用的。用复制/移动不是很实用。

【讨论】:

  • 谢谢spatial action 在这种情况下是什么意思?
  • 我提供了shared_ptr 的示例,以表明移动不仅可以复制值,还可以清除原始值。如果你尝试对 double 做同样的事情,你会看到创建了简单的副本。
【解决方案4】:

我假设您对移动语义感到困惑。如果您必须保持旧数据属于旧位置,则无法使用移动语义。移动语义意味着将数据从旧数据移到新数据。

格林威治标准时间 18:50

#include <iostream>
#include <vector>

#include <cstdlib>
#include <ctime>

#include <cstdint>

int main()
{
    std::srand(std::time(nullptr));

    const int LEN_SHAPE = 1024;
    std::vector<double> a;
    int n = LEN_SHAPE;
    while (n--)
    {
        a.push_back( ((double)std::rand() / RAND_MAX) * std::numeric_limits<double>::max() );
    }

    std::vector<double> newData(a.size(), 0);
    std::vector<double> oldData( std::move( a ));
    std::copy(oldData.begin(), oldData.end(), newData.begin());

}

std::vector oldData( std::move( a )); 是移动语义,在此之后检查向量 a 中剩余的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2013-06-05
    • 2014-05-07
    • 1970-01-01
    • 2013-08-12
    • 2018-07-09
    • 1970-01-01
    相关资源
    最近更新 更多