【问题标题】:Iterate over vector using loop c++使用循环 C++ 遍历向量
【发布时间】:2021-06-26 21:24:42
【问题描述】:

假设我有一个 long long 元素的向量:

std::vector<long long>V {1, 2, 3};

我已经看到,为了迭代向量,您可以这样做:

for (auto i = v.begin() ; i != v.end() ; i++)
   cout<<*i;

i++ 表示i 增长了1,但是地址不应该增加8 个字节来打印下一个元素吗?所以 for 循环的“增长”部分(对于任何类型)应该如下所示:

i += sizeof(v[0]);

我假设一个地址可以容纳 1 个字节,所以如果一个整数的起始地址是 1000 ,那么它的总分配将由地址表示:1000 、 1001 、 1002 、 1003。我想了解内存更好,如果您能帮助我,我将不胜感激。

【问题讨论】:

  • 更简单:for (auto&amp;&amp; value : V).
  • 你大概有int* pi = /*..*/; char* pc = reintepret_cast&lt;char*&gt;(pi); assert(pc + sizeof(int) == reintepret_cast&lt;char*&gt;(pi + 1))

标签: c++ arrays memory vector


【解决方案1】:

当你增加一个指针时,它会增加指针类型的“大小”。请记住,对于给定的指针ii[0] 是第一个元素,等效于*(i + 1)

迭代器倾向于以非常相似的方式工作,因此它们的操作很熟悉,由于operator*operator-&gt; 的实现方式,它们感觉像指针。

换句话说,i++ 的含义完全取决于i 是什么以及operator++ 将对该类型做什么。看到++ 并不意味着+1。对于迭代器,它有一个非常具体的含义,这完全取决于类型。

对于std::vector,它将指针向上移动到下一个条目。对于其他结构,它可能会导航链接列表。您可以编写自己的类,在其中进行数据库调用、从磁盘读取文件或基本上任何您想要的。

现在,如果您改为使用i += sizeof(v[0]),那么您将在数组中向上移动任意数量的位置。这取决于该条目的大小,这在很大程度上取决于您的ISA

std::vector 非常简单,它只是一个像数组一样处理的直接内存块。你甚至可以通过data() 函数获得指向它的指针。

换句话说,将i++ 视为“上移一个索引”而不是“上移一个字节”。

【讨论】:

    【解决方案2】:

    您编写此代码的方式的好处之一是您无需担心字节。

    iauto 类型掩盖了它是向量迭代器的事实,换句话说,是一种特殊类型,旨在访问 long long 向量的成员。这意味着*i 的计算结果是从当前正在索引的向量i 的任何成员中提取的long long,因此i++ 推进i 以索引向量的下一个成员。

    现在,就低级实现而言,1, 2, 3 的值可能位于相邻的 8 字节内存块中,i 可能实现为指针,而递增 i 可能通过添加来实现8 到它的价值,但这些假设中的每一个都将取决于您的架构和编译器的实现。正如我所说,这可能是您无需担心的事情。

    【讨论】:

    • "值 1、2、3 可能位于相邻的 8 字节内存块中" 不——它是一个很长的长度。 C++11 要求它至少为 64 位。但是,您可以确定它们占用的内存是连续的,因为这是 std::vector 的要求之一
    • 谢谢!!还有一个问题:一个地址是否指向一个字节?
    • @UKMonkey 那么你会如何措辞呢?坐在绝对相邻且每个至少 8 个字节的内存块中,但在今天的计算机上可能仅此而已?我试图做一个简单的解释。
    • @asddsdsadsa 我不确定回答这个问题是否会澄清任何事情。指针存储一个地址,是的,从技术上讲,这是单个字节的位置,ie 用于存储您感兴趣的long long 的第一个字节。至少,在允许每个字节的系统上要解决。然而,从“指向long long”的指针的角度来看,内存被划分为(可能)8 字节的块,并且指向其中之一。
    猜你喜欢
    • 2015-05-21
    • 2012-01-22
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多