【问题标题】:How to manually assign vector's size?如何手动分配向量的大小?
【发布时间】:2019-01-30 16:44:43
【问题描述】:

在我的应用程序中,有一部分需要我制作容器的副本。目前我使用 std::vector (但可能会考虑使用其他东西)。应用程序对延迟非常敏感。所以,我一直在寻找一种方法来尽可能快地复制矢量。我发现 memcpy 比其他任何东西都做得更好。但是,它不会改变向量的内部大小。 IE。 vector.size() 仍然会给我 0。

我知道我走的是哪条路。我不介意扔掉安全检查。我知道有多少元素被复制。我不想使用 vector.resize() 来更改目标向量的大小(这是一个缓慢的操作)。

问题:

std::vector<my_struct> destination_vector;
destination_vector.reserve(container_length);
std::memcpy(destination_vector.data(), original_vector.data(), sizeof(my_struct)*container_length);

在上面的代码之后,我需要告诉我的destination_vector 它的大小。我该怎么做?

谢谢。

【问题讨论】:

  • 我会仔细检查文档,vector 有一个名为 resize 的方法
  • 这是一个缓慢的操作 有多慢?你测量了吗?
  • 编译器已经使用了memcpy,如果你做得对的话...godbolt.org/z/7Bp4BF
  • 心理调试:my_struct 不是一个平凡的类型,所以memcpy 的任何使用都是 UB,编译器试图从自身中保存 OP。
  • @PaulSanders 如果调整大小小于以前的大小,则不允许重新分配向量。

标签: c++ vector memcpy


【解决方案1】:
  1. 必须在使用 memcpy() 将内容复制到该向量之前实际 resize()

    destination_vector.resize(container_length);

    但最好首先避免使用memcpy(),并使用机制复制vector提供的vector内容,正如其他答案中所建议的那样:

    std::vector&lt;my_struct&gt; destination_vector(original_vector);

    或者如果destination_vector 实例已经存在:

    destination_vector.insert(destination_vector.begin(), original_vector.begin(), original_vector.end);

    或者,如果您不再需要原始内容,则最快:

    destination_vector.swap(original_vector);

    所有这些变体都将与您的memcpy()variant 一样快甚至更快。如果您遇到缓慢,请参阅 2.:

  2. my_struct 中可能有一个重要的默认构造函数。删除它,或者插入一个简单的(空的)默认构造函数来加快速度(以避免构造许多你从不使用的元素)。

  3. 如果my_struct包含非POD数据成员(如std::string),则根本不能使用memcpy()

(旁注:您很少想调用reserve()vector 以这样一种方式维护自己的内部存储,即始终以指数方式分配比实际需要更多的内存,以避免在频繁追加时频繁调整大小/复制元素。)

resize() 不是一个缓慢的操作。它与任何内存分配一样快。

my_struct 是否有一个重要的默认构造函数?删除它并手动进行初始化。这可能是您说resize() 很慢的原因。它实际上会构造你的对象。但是,由于您显然可以memcpy() 您的对象,因此您可能可以使用一个琐碎(空)的默认构造函数。

【讨论】:

  • 感谢您的及时回复。但是,我特别提到,就延迟而言,我无法容忍调整大小。
  • @Aleksey 它仍然是必需的。任何会改变size 的东西都会(以一种或另一种方式)初始化添加的元素。
  • "一般不需要调用reserve()。"这不是真的。 reserve 在您知道要插入多少个元素的同时仍然使用push_backemplace_back 或以其他方式一次添加一个元素时很有用,尤其是使用std::back_inserter
  • @Francois:是的,它在特殊情况下很有用。但是,在您的示例中,没有必要调用 reserve()beforehand,因为 vector 使用指数增长。因此,一次添加一个元素仍然具有线性复杂性。
  • 由于我的构造函数,调整大小可能看起来很慢。我必须创建它才能将我的结构放置到向量中。构造函数被称为琐碎的标准是什么?
【解决方案2】:

如何手动分配向量的大小?

你不能。您只能通过插入、清除、调整大小等添加或删除元素的修改功能来修改向量的大小。

在上面的代码之后,我需要告诉我的destination_vector 它的大小。我该怎么做?

上面提到的代码有未定义的行为,所以你在它之后做什么都没有关系。

复制向量的一种简单有效的方法是:

std::vector<my_struct> destination_vector(original_vector);

【讨论】:

  • Nitpick:这假设 container_length == original_vector.size()。我希望是这样,这比我的变体更好。
  • @Caleth 好点。这是如何复制向量/容器的答案。如果container_length 具有除original_vector.size() 之外的其他特殊含义,则此示例具有不同的行为。
  • container_length 确实等于 original_vector.size()
  • 我不得不说这个答案提供了所有建议中最快的方法。仍然不是我需要的。但我感谢所有的帮助。显然,我需要进一步教育自己。
【解决方案3】:

您的 sn-p 具有未定义的行为,即使您有 reserved 空间,您也不能将 memcpy 放入空向量中。 memcpy any my_struct 对象也可能是未定义的行为,如果它不是 TriviallyCopyable 类型。

您可以直接将向量构造为源的副本。 很可能如果my_struct 是 TriviallyCopyable,您的编译器将发出与原始 sn-p 相同(或更快)的代码。

std::vector<my_struct> destination_vector(original_vector.begin(), original_vector.begin() + container_length);

【讨论】:

  • 显然我的结构不是简单可复制的。这可以解释为什么 memcpy 和常规副本之间存在如此大的差异。谢谢。
猜你喜欢
  • 2015-05-24
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
  • 2022-06-21
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 2016-03-18
相关资源
最近更新 更多