关于C++中向量的问题

8

我看到一些用C++编写的代码,如下所示:

#include <algorithm>
#include <iostream> 
#include <vector>

using namespace std;

int main() {
    int iarr[] = {30, 12, 55, 31, 98, 11, 41, 80, 66, 21};
    vector<int> ivector(iarr, iarr + 10);
}

在上面的代码中,我将 iarriarr+10 传递给 ivector(iarr, iarr + 10) 来创建一个新的向量,这是构造 vector 的正确方式吗?我查看了 STL 文档,但没有提到这一点,这样做是否被允许?
另外,数组 iarr 包含 10 个元素,我应该使用 ivector(iarr, iarr+9) 吗?

2
我不太明白你的问题,能否再详细说明一下? - MGZero
我认为最好的方法是 ivector(&iarr[0], &iarr[0] + 10); - aligray
@aligray:有什么首选的原因吗?它们完全等效,只是你可以输入更多字符。 - Jon
2
以防iarr的大小发生变化。 vector<int> ivector(iarr, iarr + (sizeof(iarr)/sizeof(iarr[0]))); - Martin York
@Jon 因为让数组衰减为指针是 C 风格的代码。我也认为这样看起来语义更清晰。 :) - aligray
显示剩余3条评论
7个回答

12

是的,允许这样做,而且你做得没错。

你正在调用这个模板构造函数:

template<class InputIterator>
   vector(
      InputIterator _First,
      InputIterator _Last
   );

模板参数InputIteratorint*(这是表达式iarriarr + 10的类型)。

由于文档规定_Last必须指向范围中的最后一个元素之外的一个元素,所以+10也是正确的,可以复制数组中的全部10个元素(iarr+9指向最后一个元素,iarr+10指向最后一个元素之外的一个元素)。


我认为值得指出的是,指针是随机访问迭代器模型,因此也是输入迭代器模型。 - pmr
@pmr:没错,但在我看来,这些信息对OP没有任何帮助。一切都有它自己的时间。 - Jon
在template<class InputIterator>中,InputIterator是什么?_First和_last是InputIterator,但我们传递的是arrar1(数组的地址),这是如何工作的? - user707549
@ratzip - 这就是pmr在上面的评论中所指的。指针是一个有效的迭代器。 - Bo Persson
@ratzip:构造函数是模板化的InputIterator是给其模板参数命名的名称;我们可以使用任何名称,但“InputIterator”很好,因为它描述了此构造函数对用作InputIterator的类型所具有的要求。所使用的类型是int [],根据C++规则,它会衰减int *,并且任何类型的指针都满足输入迭代器的要求(实际上,正如pmr所说,任何指针都满足随机访问迭代器的更高要求)。 - Jon
最好这样做,而不是硬编码为10的值。vector<int> ivector(iarr, (sizeof(iarr)/sizeof(*iarr))); - Vijay

5

数组的简单辅助工具:

template <typename T, size_t N>
size_t size(T(&)[N]) { return N; }

template <typename T, size_t N>
T* begin(T(&array)[N]) { return array; }

template <typename T, size_t N>
T* end(T(&array)[N]) { return array + N; }

现在您可以编写以下内容:
int main() {
  int const arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  std::vector<int> vec(begin(arr), end(arr));
}

不必再担心数组的大小,它将自动计算。


3

是的,这是std::vector的构造函数。它就是这个:

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

它需要两个迭代器(在您的情况下是指针),一个指向要初始化向量的元素序列的开头,另一个指向结尾。最后一个参数是可选的,除非您使用自定义分配器,否则不需要它。
结束的迭代器应该是您想要包含的最后一个元素的下一个位置。因此,如果您想要从iarr [0]iarr [9]的所有元素,则需要传入iarr + 10

1

它使用迭代器和原始的iarr[]来分配一个向量。有十个元素,+10是一个适当的迭代,因为它比结尾多一步。这就是向量的工作方式 - 它必须指向结尾的下一个位置。它正在将数组的内容复制到向量中。更明确地说,它使用此模板创建向量:

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

迭代构造函数:在 first 和 last 之间进行迭代,将元素序列的每个副本设置为容器的内容。

1

如果你查看文档这里,你会发现这段代码确实是被允许的。

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

参数指定的范围遵循通常的约定 [first, last[,因此如果您想要复制整个数组,则传递iarr + 10是正确的。


0

是的,这是允许的,ivector 将包含 10 个元素。而且不是 9,因为结束迭代器应该是 超过末尾一步。如果你知道什么是范围,那么这个范围将由此范围表示:[beginning, end)。换句话说,包括第一个,一直到但不包括最后一个。

因为 STL(C++ 标准库 cough)是全部模板,任何支持运算符 ++*(解引用运算符)的内容都可以作为迭代器传递到向量构造函数中。这个属性使得同样的代码可同时用于指针和 vector 迭代器。标准库设计的最佳实践。


0

是的,在函数main()的最后一行调用了std::vector的构造函数。请查看这里以查看所有向量构造函数重载。第三个构造函数在此处使用。它的参数是模板类型的迭代器(此处使用的模板参数为int,因此迭代器的类型为int*)。第二个参数是指向第一个不会被复制到向量中的序列元素的迭代器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接