使用指针写入std容器

时间:2014-10-09 20:46:16

标签: c++ pointers vector iterator

我希望能够创建一个固定长度的容器(vectordeque?)来执行缓冲区,然后给另一个对象向量指向该位置它们被允许写入的缓冲区。

示例(不可编译的代码)

class Item {
  *p //pointer to a place in the vector
  vector<int> values
}

vector<Item> items;

for(auto item : items) {
  for(auto value : values) {
    buffer[p] = item->value
    ++(item->p);
  }
}

但是,我不确定如何将每个Item的关系清楚地表明他们应该在缓冲区中开始写作。

我应该注意,对于items上的每次迭代,最终缓冲区具有已知的固定大小 - 但在函数调用之间,Items的数量可能会发生变化。

感谢,

3 个答案:

答案 0 :(得分:4)

如果我已正确理解了这个问题(我不确定),你应该使用索引,而不是指针或迭代器,因为它是缓冲区起始点的相对偏移量,而不是通过更改缓冲区而无效的绝对地址。

class Item
{
  size_t pos;  // index into the buffer
  vector<int> values;
};

vector<Item> items;
// ...
std::vector<int> buffer;
buffer.resize(N);
for (auto& item : items)
{
  assert(buffer.size() >= (item.pos + item.values.size()));
  std::copy(std::begin(item.values), std::end(item.values),
            std::begin(buffer)+item.pos);
}

这适用于vectordeque作为缓冲区(或其他任何带有RandomAccessIterators的内容),但因为您似乎不需要在开始时添加/删除元素缓冲区(仅调整一次并分配给现有元素)然后没有理由使用deque. Therefore you should prefer vector`,除非您需要其他容器之一的特定特征,否则它通常应该是容器的默认选择

我不知道你打算如何设置Item::pos值,也许这有意义:

size_t pos = 0;
for (auto& item : items)
{
  item.pos = pos;
  pos += item.values.size();
  assert(buffer.size() >= pos);
  std::copy(std::begin(item.values), std::end(item.values),
            std::begin(buffer)+item.pos);
}

这会将每个项目依次放入缓冲区,并动态记录位置。

这甚至可以在不事先知道总缓冲区大小的情况下工作,根据需要调整缓冲区的大小:

size_t pos = 0;
for (auto& item : items)
{
  item.pos = pos;
  pos += item.values.size();
  if (buffer.size() < pos)
    buf.resize(pos);
  std::copy(std::begin(item.values), std::end(item.values),
            std::begin(buffer)+item.pos);
}

因为您正在存储索引而不是绝对地址,所以即使在调整缓冲区大小并将其内容重新定位到不同的内存块之后,它仍会继续工作。

答案 1 :(得分:2)

  

我应该注意,对于items上的每次迭代,最终缓冲区具有已知的固定大小 - 但在函数调用之间,Items的数量可能会发生变化。

正如我的评论中所述,只有std::vector<whatever>允许更改向量时,您将为push_back()中包含的值指定和跟踪的指针和引用不稳定。 ,erase()或此类任何其他操作。


虽然,您可以选择

  • 请参阅向量的索引。这些 将是稳定的 ,即使std::vector<>需要重新分配和复制。

  • 使用smart pointers之类的 std::unique_ptr<>std::shared_ptr<>存储在std::vector<>而不是实例副本中。

这完全取决于您的实际使用情况,这是正确的方法。

答案 2 :(得分:0)

正如其他人已经评论过的那样,我不确定你想要实现的目标,但是你的原始代码并不是那些可以编译并具有明确定义(尽管是无用的)行为的东西。< / p>

我想您可能打算写下以下内容:

#include <vector>
#include <iostream>

struct Item
{
  std::vector<int>::iterator p;
  std::vector<int> values;

  Item() : values {'H', 'A', 'P', 'P', 'Y'}
  {
    this->p = values.begin();
  }
};

std::ostream&
operator<<(std::ostream& os, const Item& item)
{
  os << "[";
  for (std::size_t i = 0; i < item.values.size(); ++i)
    os << (i ? ", " : "") << item.values.at(i);
  os << "]";
  return os;
}

int main()
{
  std::vector<Item> items {4};
  for (auto& item : items)
    {
      for (auto value : item.values)
        {
          *(item.p) = value;  // Note: self-assignment with no effect
          ++(item.p);
        }
    }
  for (auto& item : items)
    std::cout << item << std::endl;
}

这个特别的程序表现良好但是使用这种数据结构,你很可能迟早会把自己射中脚。可能有更好的解决方案。