如何将数组的内容附加到 std::vector?
How to append the content of arrays to a std::vector?
我有两个数组
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)
的循环并将单个元素推回向量。
当我返回时,是否能保证插入的值顺序正确?
要将元素插入 std::vector
个 float
中,您可以使用 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
中的元素顺序与 vertices
和 normals
中的相同。
Do we need to reserve the memory before inserting the Arrays ?
从技术上讲,没有。但是保留内存可能有助于避免不必要的重新分配。
编辑。
cppreference 中 std::vector::reserve
的 Notes 部分内容如下:
When inserting a range, the range version of insert()
is generally preferable as it preserves the correct capacity growth behavior, unlike reserve()
followed by a series of push_back()
s.
我的回答中的食谱有效,但 JeJo 中的那个应该是首选。
您可以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));
[...] running a loop based on the sizeof(Array)
and push back
individual element to the vector. Would that guarantee that the values
inserted are in the correct sequence when I access them back?
是的,的确如此。请记住,您可以使用 std::size
to find the size of the array, if you have access to c++17 或更高版本的编译器。
您可能希望将这两个数组追加到现有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)),...);
}
将 vertices
和 normals
附加到现有的 std::vector<float>
变为:
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;
}
从数组 vertices
和 normals
创建一个新向量归结为一行:
auto vec = create_vector(vertices, normals);
你不限于两个数组。由于它们的 variadic 性质,您实际上可以为这些函数模板提供 任意数量的数组 ,例如:
auto vec = create_vector(vertices, vertices, normals, vertices, normals);
上面的代码行如您所料,即它创建了一个新向量,该向量由 vertices
、vertices
(再次)、normals
中的元素串联而成vertices
和 normals
.
在任何情况下,对于 append_to_vector()
的每次调用,最多只会执行一次重新分配 因为对 std::vector::reserve()
的调用确保了内存插入新元素所需的元素在插入之前可用。
我有两个数组
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)
的循环并将单个元素推回向量。
当我返回时,是否能保证插入的值顺序正确?
要将元素插入 std::vector
个 float
中,您可以使用 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
中的元素顺序与 vertices
和 normals
中的相同。
Do we need to reserve the memory before inserting the Arrays ?
从技术上讲,没有。但是保留内存可能有助于避免不必要的重新分配。
编辑。
cppreference 中 std::vector::reserve
的 Notes 部分内容如下:
When inserting a range, the range version of
insert()
is generally preferable as it preserves the correct capacity growth behavior, unlikereserve()
followed by a series ofpush_back()
s.
我的回答中的食谱有效,但 JeJo 中的那个应该是首选。
您可以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));
[...] running a loop based on the
sizeof(Array)
and push back individual element to the vector. Would that guarantee that the values inserted are in the correct sequence when I access them back?
是的,的确如此。请记住,您可以使用 std::size
to find the size of the array, if you have access to c++17 或更高版本的编译器。
您可能希望将这两个数组追加到现有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)),...);
}
将 vertices
和 normals
附加到现有的 std::vector<float>
变为:
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;
}
从数组 vertices
和 normals
创建一个新向量归结为一行:
auto vec = create_vector(vertices, normals);
你不限于两个数组。由于它们的 variadic 性质,您实际上可以为这些函数模板提供 任意数量的数组 ,例如:
auto vec = create_vector(vertices, vertices, normals, vertices, normals);
上面的代码行如您所料,即它创建了一个新向量,该向量由 vertices
、vertices
(再次)、normals
中的元素串联而成vertices
和 normals
.
在任何情况下,对于 append_to_vector()
的每次调用,最多只会执行一次重新分配 因为对 std::vector::reserve()
的调用确保了内存插入新元素所需的元素在插入之前可用。