【问题标题】:How to append the content of arrays to a std::vector?如何将数组的内容附加到 std::vector?
【发布时间】:2019-12-26 07:29:30
【问题描述】:

我有两个数组

float vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};  

float normals[] = {
    0.0, 0.0f, 1.0f,
     0.0f, 0.0f, 1.0f,
     0.0f,  0.0f, 1.0f
}; 

我首先想将vertices 数组添加到std::vector<float>,然后将normals 数组插入到向量中。

我能想到的是基于sizeof(Array) 运行一个循环并将单个元素推回向量。

当我访问它们时,这能保证插入的值的顺序正确吗?

【问题讨论】:

  • 你最后一个问题的答案是YES

标签: c++ arrays algorithm c++17 stdvector


【解决方案1】:

你可以std::vector::insert向量末尾的元素。

#include <iterator> // std::cbegin, std::cend, std::size
#include <vector>
std::vector<float> vec;
// reserve the memory for unwated reallocations.
vec.reserve(std::size(vertices) + std::size(normals));

vec.insert(vec.end(), std::cbegin(vertices), std::cend(vertices));
vec.insert(vec.end(), std::cbegin(normals), std::cend(normals));

[...] 基于sizeof(Array) 运行循环并推回 向量的单个元素。是否可以保证这些值 当我重新访问它们时,插入的顺序是否正确?

是的,确实如此。请记住,如果您可以访问 或更高版本的编译器,则可以使用 std::size 来查找数组的大小。

【讨论】:

  • 也可以先用vertices构造vec,然后用insert()添加normals的元素。成本(可能)是额外的重新分配。
  • 这不会阻止额外的重新分配。如果需要,这只会导致 reserve() 进行额外的重新分配。
【解决方案2】:

您可能希望将这两个数组追加现有 std::vector创建一个新 数组。在这两种情况下,您很可能希望一次性保留插入所需的所有内存,以避免额外的不必要的重新分配。

对于前一种情况,可以使用如下函数模板:

template<size_t... Ns>
void append_to_vector(std::vector<float>& vec, float (&...arrs)[Ns]) {
   constexpr auto num_elements_to_append = sizeof...(Ns);
   vec.reserve(vec.size() + num_elements_to_append);
   (vec.insert(vec.end(), std::cbegin(arrs), std::cend(arrs)),...);
}

verticesnormals 附加到现有的std::vector&lt;float&gt; 变为:

std::vector<float> vec; // your existing vector
// ...
append_to_vector(vec, vertices, normals);

对于后一种情况——即,你想从这两个数组中创建一个新向量——你可以使用下面的函数模板,create_vector,然后调用append_to_vector

template<size_t... Ns>
std::vector<float> create_vector(float (&...arrs)[Ns]) {
   std::vector<float> vec; 
   append_to_vector(vec, arrs...);
   return vec;
}

从数组 verticesnormals 创建一个新向量归结为一行:

auto vec = create_vector(vertices, normals);

您不限于两个数组。由于它们的可变参数特性,您实际上可以为这些函数模板提供任意数量的数组,例如:

auto vec = create_vector(vertices, vertices, normals, vertices, normals); 

上面的行如您所料,即它创建了一个新向量,该向量由verticesvertices(再次)、normalsverticesnormals 中的元素串联而成。

在任何情况下,对于每次调用 append_to_vector(),只会执行一次重新分配最多,因为对 std::vector::reserve() 的调用确保插入新元素所需的内存在之前可用插入。

【讨论】:

    【解决方案3】:

    要将元素插入到floats 的std::vector 中,可以使用std::copy

    std::vector<float> my_vector;
    my_vector.reserve(std::size(vertices) + std::size(normals)); // optional
    
    std::copy(std::begin(vertices), std::end(vertices), std::back_inserter(my_vector));
    std::copy(std::begin(normals), std::end(normals), std::back_inserter(my_vector));
    

    my_vector 中的元素顺序将与verticesnormals 中的相同。

    在插入数组之前我们需要保留内存吗?

    从技术上讲,没有。但是保留内存可能有助于避免不必要的重新分配。

    编辑。

    cppreference 中std::vector::reserveNotes 部分内容如下:

    在插入范围时,insert() 的范围版本通常更可取,因为它保留了正确的容量增长行为,这与 reserve() 后跟一系列 push_back()s 不同。

    我的答案中的配方有效,但应该首选 JeJo 的配方。

    【讨论】:

    • 插入数组之前需要预留内存吗?
    • @shomit,没有。但保留内存可能有助于避免不必要的重新分配。
    猜你喜欢
    • 2020-05-27
    • 2010-09-25
    • 2017-07-20
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    相关资源
    最近更新 更多