【问题标题】:Using pointers to write to a std container使用指针写入 std 容器
【发布时间】:2014-12-04 22:15:57
【问题描述】:

我希望能够创建一个固定长度的容器 (vector?deque?) 来充当缓冲区,然后为另一个对象向量提供一个指向缓冲区位置的指针。允许写入。

示例(不可编译的代码)

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 的数量可能会发生变化。

谢谢,

【问题讨论】:

  • 你的意思是像 std::array?
  • 我不认为std::array 会起作用,因为对于我的项目的每次迭代,最终缓冲区大小都是已知的,但在函数调用之间items 的大小可能会改变。我也不确定如何给每个Item 一个指向它应该开始写入的位置的指针。
  • then use pointers to have items write to certain parts of the vector to create a buffer 如果该向量被调整大小,您设置的那些指针最终可能指向垃圾,因为向量的迭代器可能会失效。
  • 我仍然迷失在解析 question 中。 “...使用指针让项目写入向量的某些部分以创建缓冲区” - 写入向量不会“创建”任何东西。你有没有机会举一个实际的例子。 IE。 “假设我的向量看起来像......我希望能够做到......”。
  • 指向 std::vector&lt;&gt; 中包含的值的指针不稳定。这不是一个好主意!考虑使用索引,甚至 smart pointers,如果你真的需要的话。

标签: c++ pointers vector iterator


【解决方案1】:

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

正如我的评论中所述,只要push_back()erase() 允许更改向量,您将获取并跟踪 std::vector&lt;whatever&gt; 中包含的值的指针和引用并不稳定或任何其他此类操作。


不过,你可以选择

  • 参考向量的索引。这些将是稳定的,即使std::vector&lt;&gt; 需要重新分配和复制。

  • 使用smart pointers 喜欢 将std::unique_ptr&lt;&gt;std::shared_ptr&lt;&gt; 存储在std::vector&lt;&gt; 而不是实例副本中。

这完全取决于您的实际用例,这将是正确的方法。

【讨论】:

    【解决方案2】:

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

    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 prefervector`,除非您需要其他容器之一的特定特征,否则它通常应该是您的默认容器选择。

    我不知道你打算如何设置 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);
    }
    

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

    【讨论】:

      【解决方案3】:

      正如其他人已经评论的那样,我不确定您要实现什么目标,但您的原始代码与可以编译并且具有明确定义(尽管相当无用)的行为的东西相距不远。

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

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

      这个特定的程序表现良好,但使用这种数据结构,你很可能迟早会在​​脚下开枪。可能有更好的解决方案。

      【讨论】:

        猜你喜欢
        • 2015-04-30
        • 2012-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多