繁体   English   中英

使用重复模式初始化std :: vector

[英]Initializing std::vector with a repeating pattern

我目前正在使用OpenGL,创建一个“纹理缓存”来处理加载图像并使用OpenGL缓冲它们。 如果无法加载图像文件,则需要回退到我在构造函数中硬编码的默认纹理。

我基本上需要做的是创建一个统一颜色的纹理。 这不是太难,它只是一个像素*颜色通道的数组。

我正在使用std :: vector来保存初始数据,然后再上传OpenGL。 我遇到的问题是我无法找到有关使用重复模式初始化矢量的最佳方法的任何信息。

我遇到的第一种方法是使用循环。

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);
}

然而,这似乎是低效的,因为向量必须多次调整自身大小。 即使我先保留空间并执行循环,它仍然没有效率,因为内容将在循环之前归零,这意味着每个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中提取内存,操作系统可能仍会将其归零。)它不会更改向量的大小,因此push_back和朋友仍然以相同的方式工作。

您可以使用reserve来预先分配向量; 这将避免重新分配。 您还可以定义一个小序列(可能是C样式向量:

char const init[] = { 0, 0, 255, 255 };

并将其插入到向量的末尾:

for ( int i = 0; i < pixelCount; ++ i ) {
    v.insert( v.end(), std::begin( init ), std::end( init ) );
}

这只比使用循环中的四个push_back稍微更有效,但更简洁,也许会使你更清楚你正在做什么,虽然只是轻微的:最大的优势可能是能够为初始化序列命名(例如defaultBackground东西)。

最有效的方法是最不起作用的方式。

不幸的是,push_back(),insert()等必须在向量工作时保持向量的大小(),这在紧密循环中执行时是冗余操作。

因此,最有效的方法是分配内存一次,然后将数据直接复制到其中,而不保留任何其他变量。

它是这样完成的:

#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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM