【问题标题】:Why iterator is not dereferenced as an lvalue为什么迭代器没有被取消引用为左值
【发布时间】:2016-10-13 19:19:45
【问题描述】:

如果我的问题不包含所有相关信息,我们深表歉意。请发表评论,我会做出相应的修改。

我在 Win7 上使用带有 MinGW 和 gcc 的 CLion


我一直在尝试使用循环缓冲区并遇到boost::circular_buffer,但对于我的项目规模,我想使用Pete Goodlife 的circular buffer,这似乎是一个可靠的实现,仅在一个.hpp 中。

注意:感谢Boost dependencies and bcp,我知道如何减少对 boost 的依赖。

但是,下面的 Pete 实现示例的行为与预期不同,即 std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin()); 的结果是 empty。我想了解原因并可能纠正其行为。

遵循 MWE:

#include "circular.h"
#include <iostream>
#include <algorithm>

typedef circular_buffer<int> cbuf_type;

void print_cbuf_contents(cbuf_type &cbuf){
  std::cout << "Printing cbuf size("
            <<cbuf.size()<<"/"<<cbuf.capacity()<<") contents...\n";
  for (size_t n = 0; n < cbuf.size(); ++n)
    std::cout << "  " << n << ": " << cbuf[n] << "\n";

  if (!cbuf.empty())  {
    std::cout << "  front()=" << cbuf.front()
              << ", back()=" << cbuf.back() << "\n";
  }  else  {
    std::cout << "  empty\n";
  }
}

int main()
{
  cbuf_type cbuf(5);
  for (int n = 0; n < 3; ++n) cbuf.push_back(n);
  print_cbuf_contents(cbuf);

  cbuf_type df(5);
  std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin());
  print_cbuf_contents(df);
}

打印以下内容:

Printing cbuf size(3/5) contents...
  0: 0
  1: 1
  2: 2
  front()=0, back()=2
Printing cbuf size(0/5) contents...
  empty

不幸的是,作为 C++ 的新手,我无法弄清楚为什么 df.begin() 迭代器没有被取消引用为左值。

我怀疑罪魁祸首是(或不完全理解)Pete 的circular.h 中第 72 行的circular_buffer_iterator 的成员调用:

elem_type &amp;operator*() { return (*buf_)[pos_]; }

非常感谢任何帮助。

【问题讨论】:

    标签: c++ stl circular-buffer


    【解决方案1】:

    您作为输出迭代器传递的迭代器被取消引用并被视为左值,并且您期望的数据很可能实际上存储在循环缓冲区的缓冲区中。

    问题是,除了实际的存储缓冲区之外,大多数容器还包含一些必须维护的内部簿记状态。 (例如:缓冲区中有多少元素,剩余多少可用空间等)。

    取消引用和增加容器不会更新内部状态,因此容器不会“知道”新数据已添加。

    考虑以下代码:

    std::vector<int> v;
    v.reserve(3);
    
    auto i = v.begin();
    *(i++) = 1; // this simply writes to memory
    *(i++) = 2; // but doesn't update the internal
    *(i++) = 3; // state of the vector
    assert(v.size() == 0); // so the vector still "thinks" it's empty
    

    使用 push_back 会按预期工作:

    std::vector<int> v;
    v.reserve(3);
    
    v.push_back(1); // adds to the storage AND updates internal state
    v.push_back(2);
    v.push_back(3);
    
    assert(v.size() == 3); // so the vector "knows" it has 3 elements
    

    在您的情况下,您应该使用 std::back_inserter,这是一个迭代器,每次取消引用时都会在容器上调用“push_back”:

    std::adjacent_difference(
        cbuf.begin(), cbuf.end(),
        std::back_inserter(df));
    

    【讨论】:

    • 问题是,Pete 的容器声称它是 STL 兼容的,我希望它在向量上的行为类似于 exampleadjacent_difference()。我需要引入什么调整来触发状态更新?
    • 在阅读了更多关于back_inserter() in this post 的内容后,我想我开始理解了,这基本上描述了我的用例。但是,我不确定为什么 cppreference 会包含这样的示例...
    【解决方案2】:

    std::adjacent_difference 写入结果迭代器。在您的情况下,该结果迭代器指向 df,其大小为 0,容量为 5。这些写入将进入 df 的保留内存,但不会更改容器的大小,所以 size 仍然是 0,保留的容器空间的前 3 个 int 会有你的差异。为了看到结果,被写入的容器必须已经有数据存储在被写入的槽中。

    所以要查看结果,你必须在差异之前将数据放入循环缓冲区,然后将容器调整为适当的大小(基于adjacent_difference返回的迭代器。

    【讨论】:

    • 这听起来像是双重工作,填充df,然后覆盖它们。我不知道 boost::circular_buffer 是不是这样,但我没有这个问题。
    猜你喜欢
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 2012-11-24
    • 2019-10-17
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    相关资源
    最近更新 更多