使用重复模式初始化std::vector
Initializing std::vector with a repeating pattern
我目前正在使用OpenGL,创建一个"纹理缓存",用于处理加载图像并使用OpenGL缓冲它们。如果无法加载图像文件,则需要返回到我在构造函数中硬编码的默认纹理。
我基本上需要做的是创建一个统一颜色的纹理。这并不太难,它只是一个大小为像素*颜色通道的数组。
在我上传OpenGL之前,我目前使用std::vector来保存初始数据。我遇到的问题是,我找不到任何关于用重复模式初始化向量的最佳方法的信息。
我想到的第一种方法是使用循环。
std::vector<unsigned char> blue_texture;
for (int iii = 0; iii < width * height; iii++)
{
blue_texture.push_back(0);
blue_texture.push_back(0);
blue_texture.push_back(255);
blue_texture.push_back(255);
}
然而,这似乎效率不高,因为vector必须多次调整自身大小。即使我先预留空间并执行循环,它仍然不高效,因为内容在循环之前将被归零,这意味着每个unsigned char都要进行两次写操作。
目前我正在使用以下方法:
struct colour {unsigned char r; unsigned char g; unsigned char b; unsigned char a;};
colour blue = {0, 0, 255, 255};
std::vector<colour> texture((width * height), blue);
然后使用:
提取数据reinterpret_cast<unsigned char*>(texture.data());
还有比这更好的方法吗?我是C/c++的新手,老实说,转换指针让我害怕。
我认为你的循环解决方案是正确的。要通过删除重复的realloc调用来提高效率,请使用blue_texture.reserve(width * height * 4)
保留调用将增加分配,即容量到该大小,而不会零填充。(注意,如果从mmap中提取内存,操作系统可能仍然会将其归零。)它不改变vector的大小,因此push_back和同类函数的工作方式仍然相同。
您可以使用reserve
来预分配向量;这将避免重新分配。您还可以定义一个小序列(可能是C风格的向量):
char const init[] = { 0, 0, 255, 255 };
和循环插入到vector的末尾:
for ( int i = 0; i < pixelCount; ++ i ) {
v.insert( v.end(), std::begin( init ), std::end( init ) );
}
这只是比在循环中使用四个push_back
稍微有效一点,但是更简洁,并且可能使您所做的事情更清楚,尽管只是稍微:最大的优点可能是能够为初始化序列命名(例如defaultBackground
)。
最有效的方法是最省力的方法。
不幸的是,push_back()、insert()等操作在工作时必须维护vector的size(),在紧密循环中执行这些操作是冗余的。
因此,最有效的方法是分配一次内存,然后直接将数据复制到内存中,而不需要维护任何其他变量。是这样做的:
#include <iostream>
#include <array>
#include <vector>
using colour_fill = std::array<uint8_t, 4>;
using pixel_map = std::vector<uint8_t>;
pixel_map make_colour_texture(size_t width, size_t height, colour_fill colour)
{
// allocate the buffer
std::vector<uint8_t> pixels(width * height * sizeof(colour_fill));
auto current = pixels.data();
auto last = current + pixels.size();
while (current != last) {
current = std::copy(begin(colour), end(colour), current);
}
return pixels;
}
auto main() -> int
{
colour_fill blue { 0, 0, 255, 255 };
auto blue_bits = make_colour_texture(100, 100, blue);
return 0;
}
我会保留所需的整个大小,然后使用insert函数反复将图案添加到向量中。
std::array<unsigned char, 4> pattern{0, 0, 255, 255};
std::vector<unsigned char> blue_texture;
blue_texture.reserve(width * height * 4);
for (int i = 0; i < (width * height); ++i)
{
blue_texture.insert(blue_texture.end(), pattern.begin(), pattern.end());
}
我创建了这个模板函数,它将修改它的输入容器,使其包含count
倍于它已经包含的内容。
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Container>
void repeat_pattern(Container& data, std::size_t count) {
auto pattern_size = data.size();
if(count == 0 or pattern_size == 0) {
return;
}
data.resize(pattern_size * count);
const auto pbeg = data.begin();
const auto pend = std::next(pbeg, pattern_size);
auto it = std::next(data.begin(), pattern_size);
for(std::size_t k = 1; k < count; ++k) {
std::copy(pbeg, pend, it);
std::advance(it, pattern_size);
}
}
template<typename Container>
void show(const Container& data) {
for(const auto & item : data) {
std::cout << item << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> v{1, 2, 3, 4};
repeat_pattern(v, 3);
// should show three repetitions of times 1, 2, 3, 4
show(v);
}
输出(编译为g++ example.cpp -std=c++14 -Wall -Wextra
):
1 2 3 4 1 2 3 4 1 2 3 4
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- std::vector的包装器,使数组的结构看起来像结构的数组
- 编译器如何区分std::vector的构造函数
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 在std::vector上存储带有模板的类实例
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 为什么std::vector比数组慢
- std::vector::迭代器是否可以合法地作为指针
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 为什么std::vector和std::valarray初始化构造函数不同
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 在没有未定义行为的情况下实现类似std::vector的容器
- 如何调整 std::vector of Eigen::MatrixXd 的大小
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 如何将AERT_Allocate与 std:vector 一起使用
- 推导 std::vector::back() 的返回类型
- 如何将原始字节附加到 std::vector?
- std::vector 没有重载函数的实例与参数列表匹配
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?