简体   繁体   English

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

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

Below text is from a C++ online course. 下面的文字来自C ++在线课程。 It says that the constructor of the vector class 它说vector类的构造函数

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

can receive pointers as first ( InputIterator first ) and second parameter ( InputIterator last ). 可以接收指针作为第一个( InputIterator first )和第二个参数( InputIterator last )。

The next constructor uses iterators to initialize itself. 下一个构造函数使用迭代器进行初始化。 It will create a vector with a copy of values from first (inclusive) to last (exclusive). 它将创建一个向量,该向量具有从第一个(包含)到最后一个(不含)的值的副本。 In the most typical case, this constructor creates a new vector using elements from an already existing collection. 在最典型的情况下,此构造函数使用现有集合中的元素创建新的向量。 But due to the fact that iterators are defined as a set of operations instead of a certain type, it is also possible to use normal pointers. 但是由于将迭代器定义为一组操作而不是某种类型的事实,因此也可以使用普通指针。 This remark leads to a conclusion that you can use a normal C++ array to initialize a collection. 此评论得出一个结论,您可以使用普通的C ++数组初始化集合。 And in fact you can. 实际上,您可以。

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

I can get used to this, but I don't really understand why it is possible. 我可以习惯这一点,但是我真的不明白为什么有这种可能。 I'd like to understand this technique. 我想了解这项技术。

My question in this case (see code) is how is it possible that I can simply put an array address instead of an iterator? 在这种情况下(请参见代码),我的问题是,我怎么可能只简单地放置一个数组地址而不是一个迭代器?

In the above code an element of type int * is put as a parameter of type InputIterator . 在上面的代码中,将一个int *类型的元素作为InputIterator类型的参数。 This confuses me. 这使我感到困惑。

All the story is about what the constructs expects from an iterator. 所有的故事都是关于构造对迭代器的期望。 It expects to be able to increment it (using ++), to deference it (using *). 它期望能够增加它(使用++),以尊重它(使用*)。 An interator is simply either a class that overloads the ++ and the * operator, or a basic pointer type that naturally supports both operations. 插入器既可以是重载++和*运算符的类,也可以是自然支持这两种操作的基本指针类型。

C++ iterators are actually carefully designed to generalize the semantics of pointers and mimic their syntax (hence the operator* overload). 实际上,C ++迭代器经过了精心设计,以概括指针的语义并模仿其语法(因此, operator*重载)。

See the general discussion in the original SGI docs or the treatment of more recent C++ versions here , and note in particular that: 请参阅原始SGI文档中的一般性讨论或此处的最新C ++版本的处理,并特别注意:

  1. pointers satisfy all the requirements of RandomAccessIterators 指针满足RandomAccessIterators的所有要求
  2. RandomAccessIterators model a superset of the requirements of an InputIterator RandomAccessIterators为InputIterator需求的超集建模
  3. the std::vector constructor only requires InputIterator std::vector构造函数仅需要InputIterator

If you don't really believe #1, you may also be interested to see that the standard library explicitly provides iterator traits for raw pointers , and if you're still struggling after that, take a look at the implementation of the constructor, and reassure yourself that all operations on its arguments are well-formed for pointers. 如果您真的不相信#1,那么您可能还希望看到标准库显式地为原始指针提供迭代器特征 ,并且如果您仍在苦苦挣扎,请看一下构造函数的实现,以及请放心,针对其参数的所有操作格式都正确。

To answer your last question a pointer points to a place in memory. 要回答最后一个问题,指针指向内存中的位置。 Since memory is random access pointers can be classified as a having random access. 由于存储器是随机访问的,因此指针可以归类为具有随机访问的指针。 Iterators have the same type of classifications. 迭代器具有相同的分类类型。 cplusplus.com has a nice layout showing which type of iterator support what here . cplusplus.com的布局很好,可以显示此处支持哪种类型的迭代器。 With that we can see that input iterators are the lowest type and they can do the least amount of operations. 这样,我们可以看到输入迭代器是最低的类型,并且它们可以执行最少的操作。 Since a pointer is the same as a random access iterator and a random access iterator can do everything an input iterator can do there isn't any issue with that. 由于指针与随机访问迭代器相同,并且随机访问迭代器可以执行输入迭代器可以执行的所有操作,因此没有任何问题。

If this was the other way around and you had a function that wanted a random access iterator and you supplied a forward iterator there is no guarantee that the code would work. 如果这是相反的方法,并且您有一个需要随机访问迭代器的函数,并且提供了前向迭代器,则不能保证代码会正常工作。 This is because the function could be relying on some operation a random access iterator can do that the forward iterator can't do. 这是因为该函数可能依赖于某个操作,而随机访问迭代器可以执行此操作,而正向迭代器则无法执行。

Generally when you write this type of code and you specify what iterator type you want you specify the minimal type that allows your code to compile. 通常,当您编写这种类型的代码并指定所需的迭代器类型时,可以指定允许代码编译的最小类型。 Something that just prints the contents just needs a forward iterator as you are just traversing the contents where sorting needs a random access. 只是打印内容的东西只需要一个正向迭代器,因为您只是遍历需要随机访问的内容时。

Because an array stores it's elements in contiguous memory. 因为数组将其元素存储在连续内存中。 So if you know the size of the type, and the pointer to the first element, you can figure out the address of all the remaining elements. 因此,如果您知道类型的大小以及第一个元素的指针,则可以找出所有其余元素的地址。

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

§5.7 Additive operators §5.7加法运算符

The additive operators + and - group left-to-right. 加法运算符+和-从左到右分组。 The usual arithmetic conversions are performed for operands of arithmetic or enumeration type. 通常对算术或枚举类型的操作数执行算术转换。

For addition , either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type . 另外 ,两个操作数都应具有算术或无作用域枚举类型,或者一个操作数应是指向完全定义的对象类型的指针另一个操作数应具有整数或无作用域的枚举类型

For subtraction, one of the following shall hold: 对于减法,应满足下列条件之一:
— both operands have arithmetic or unscoped enumeration type; —两个操作数都具有算术或非范围枚举类型; or 要么
— both operands are pointers to cv-qualified or cv-unqualified versions of the same completely-definedobject type; —两个操作数都是相同完全定义对象类型的cv限定或cv非限定版本的指针; or 要么
— the left operand is a pointer to a completely-defined object type and the right operand has integral or unscoped enumeration type. —左操作数是指向完全定义的对象类型的指针,而右操作数具有整数或无作用域的枚举类型。

... ...

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. 当将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression . 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式 In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array object, provided they exist. 换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(相当于N +(P))和(P)-N(其中N的值为n)表示分别存在于数组对象的第i + n个元素和第i-n个元素中,前提是它们存在。 Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. 此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后,如果表达式Q指向数组对象的最后一个元素之后,表达式(Q)-1指向数组对象的最后一个元素。 If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; 如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则求值不会产生溢出; otherwise, the behavior is undefined. 否则,行为是不确定的。

So basically, the standard defines the arithmetic between a pointer T* and an integral type 因此,基本上,该标准定义了指针T*和整数类型之间的算术

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

To result in another T* that is n * sizeof(T) from the initial t . 从初始t得出另一个n * sizeof(T) T*

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

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