繁体   English   中英

C ++-在期望类型为Iterator的向量(或其他容器)构造函数中使用数组/指针。 那怎么可能?

[英]C++ - Using array/pointers in vector (or other container) constructor that expects type Iterator. How is that possible?

下面的文字来自C ++在线课程。 它说vector类的构造函数

 template <class InputIterator>
          vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );

可以接收指针作为第一个( InputIterator first )和第二个参数( InputIterator last )。

下一个构造函数使用迭代器进行初始化。 它将创建一个向量,该向量具有从第一个(包含)到最后一个(不含)的值的副本。 在最典型的情况下,此构造函数使用现有集合中的元素创建新的向量。 但是由于将迭代器定义为一组操作而不是某种类型的事实,因此也可以使用普通指针。 此评论得出一个结论,您可以使用普通的C ++数组初始化集合。 实际上,您可以。

#include <vector>
#include <iostream>

using namespace std;

int main()
{
    int a1[]={1,2,3,4,5,6,7,8,9,10};
    //first one
    vector<int> v1(a1, a1+10);
    cout<<"Size (v1):  "<<v1.size()<<endl;
    for(unsigned i = 0; i < v1.size(); ++i)
    {
        cout<< v1[i]<<" ";
    }
    cout<<endl;
    //second one;
    vector<int> v2(a1+5,a1+10);
    cout<<"Size (v2):  "<<v2.size()<<endl;
    for(unsigned i = 0; i < v2.size(); ++i)
    {
        cout<< v2[i]<<" ";
    }
    cout<<endl;
    return 0;
}

我可以习惯这一点,但是我真的不明白为什么有这种可能。 我想了解这项技术。

在这种情况下(请参见代码),我的问题是,我怎么可能只简单地放置一个数组地址而不是一个迭代器?

在上面的代码中,将一个int *类型的元素作为InputIterator类型的参数。 这使我感到困惑。

所有的故事都是关于构造对迭代器的期望。 它期望能够增加它(使用++),以尊重它(使用*)。 插入器既可以是重载++和*运算符的类,也可以是自然支持这两种操作的基本指针类型。

实际上,C ++迭代器经过了精心设计,以概括指针的语义并模仿其语法(因此, operator*重载)。

请参阅原始SGI文档中的一般性讨论或此处的最新C ++版本的处理,并特别注意:

  1. 指针满足RandomAccessIterators的所有要求
  2. RandomAccessIterators为InputIterator需求的超集建模
  3. std::vector构造函数仅需要InputIterator

如果您真的不相信#1,那么您可能还希望看到标准库显式地为原始指针提供迭代器特征 ,并且如果您仍在苦苦挣扎,请看一下构造函数的实现,以及请放心,针对其参数的所有操作格式都正确。

要回答最后一个问题,指针指向内存中的位置。 由于存储器是随机访问的,因此指针可以归类为具有随机访问的指针。 迭代器具有相同的分类类型。 cplusplus.com的布局很好,可以显示此处支持哪种类型的迭代器。 这样,我们可以看到输入迭代器是最低的类型,并且它们可以执行最少的操作。 由于指针与随机访问迭代器相同,并且随机访问迭代器可以执行输入迭代器可以执行的所有操作,因此没有任何问题。

如果这是相反的方法,并且您有一个需要随机访问迭代器的函数,并且提供了前向迭代器,则不能保证代码会正常工作。 这是因为该函数可能依赖于某个操作,而随机访问迭代器可以执行此操作,而正向迭代器则无法执行。

通常,当您编写这种类型的代码并指定所需的迭代器类型时,可以指定允许代码编译的最小类型。 只是打印内容的东西只需要一个正向迭代器,因为您只是遍历需要随机访问的内容时。

因为数组将其元素存储在连续内存中。 因此,如果您知道类型的大小以及第一个元素的指针,则可以找出所有其余元素的地址。

int values[10];
&values[5] == &values[0] + 5 // due to pointer arithmetic

§5.7加法运算符

加法运算符+和-从左到右分组。 通常对算术或枚举类型的操作数执行算术转换。

另外 ,两个操作数都应具有算术或无作用域枚举类型,或者一个操作数应是指向完全定义的对象类型的指针另一个操作数应具有整数或无作用域的枚举类型

对于减法,应满足下列条件之一:
—两个操作数都具有算术或非范围枚举类型; 要么
—两个操作数都是相同完全定义对象类型的cv限定或cv非限定版本的指针; 要么
—左操作数是指向完全定义的对象类型的指针,而右操作数具有整数或无作用域的枚举类型。

...

当将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式 换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(相当于N +(P))和(P)-N(其中N的值为n)表示分别存在于数组对象的第i + n个元素和第i-n个元素中,前提是它们存在。 此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后,如果表达式Q指向数组对象的最后一个元素之后,表达式(Q)-1指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则求值不会产生溢出; 否则,行为是不确定的。

因此,基本上,该标准定义了指针T*和整数类型之间的算术

T* t + n  // where n is an offset (of integral type)

从初始t得出另一个n * sizeof(T) T*

暂无
暂无

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

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