c++ - C++ STL: 可以使用STL函数透明地使用数组?

  显示原文与译文双语对照的内容
0 0

我假设STL函数只能用于STL数据容器( 像 vector ),直到我看到这一段代码:

#include <functional>
#include <iostream>
#include <numeric>
using namespace std;
int main()
{
 int a[] = {9, 8, 7};
 cerr <<"Sum:" <<accumulate(&a[0], &a[3], 0, plus<int>()) <<endl;
 return 0;
}

它编译和运行时没有任何警告或者错误,G++ 给出了正确的输出和 24.

是这样使用stl的数组函数允许 C++/STL 标准? 如果是的话,像数组这样的古老结构如何适应模板化迭代器,容器和函数的宏大STL计划? 同样,这样的使用有任何警告或细节,程序员应该小心呢?

时间:原作者:13个回答

0 0

你问一个数组。 你可以很容易的得到一个指向它元素的指针,所以它基本上归结为指针是否可以透明地和STL函数一起使用。 指针实际上是迭代器最强大的类型。 有不同种类

  • 输入迭代器: 仅向前和 one-pass,并且只读取
  • 输出迭代器: 仅向前和 one-pass,并且只写入

  • 向前迭代器:只有向前,和读/写
  • 双向迭代器:向前和向后,读/写
  • 随机访问迭代器: 任意一步向前和向后移动,并读取/写入

现在,第二个组中的每个迭代器都支持前面提到的所有迭代器的所有内容。 指针为最后一类迭代器建模- 随机访问迭代器。 你可以添加/减去任意整数,你可以读写。 除了输出迭代器之外,还有一个 operator-> 可以用来访问我们遍历的元素类型的成员。

通常,迭代器有几个typedef作为成员

  • value_type - 迭代器迭代的内容( int,bool,字符串,。)
  • 参考- 对value_type的引用
  • 指针- 指向value_type的指针
  • difference_type - 两个迭代器之间的距离是( 由 std::distance 返回) 。
  • iterator_category - 这是一个 tag-type: 它是一个表示迭代器类型的类型的typedefed 。 std::input_iterator_tagstd::random_access_iterator_tag 。 算法可以使用它来重载不同类型的迭代器( 比如 std::distance 对于随机访问迭代器更快,因为它可以返回 a - b )

当然,一个指针没有那些成员。 C++ 有一个 iterator_traits 模板并专门用于指针。 因此,如果你想要获得任何迭代器的值类型,那么

iterator_traits<T>::value_type

无论它是一个指针还是其他迭代器,它都会给出迭代器的value_type 。

所以- 是的,一个指针可以很好地和STL算法一起使用。 就像别人提到的,即使 std::vector<T>::iterator 也可以是一个 T* 。 指针是迭代器的一个非常好的例子。 因为它非常简单,但同时如此强大,它可以在一个范围内迭代。

原作者:
0 0

标准设计了迭代器来感觉和行为尽可能像指针。 同样,由于迭代器基于模板,唯一相关的事情是迭代器类型有正确的运算符定义。 结果是指针会像随机访问迭代器一样行为。

事实上,std::vector<T>::iterator的一个可能实现就是让它成为一个 T*

当然,对于数组,你没有找到有效的迭代器范围的有用的begin()end() 方法,但这就是你在C 样式数组中总是遇到的问题。

编辑:实际上,就像在注释和其他答案中提到的,如果数组不是动态的,并且还没有退化为指针,就可以实现这些函数。 但是我的基本观点是,你必须比使用标准容器更加小心。

原作者:
0 0

简短回答:STL算法通常被定义为处理各种排序的迭代器。 迭代器由它的行为定义: 它必须是 dereferenceable,*, 必须是 incrementable,还必须是 ++,其他也定义了它是哪种迭代器。 记住,STL算法是模板,所以问题是一个语法。 类似地,带有 operator()的类实例在语法上就像函数一样工作,因此可以互换使用。

指针做的每件事都是一个random-access迭代器。 因此,它是一个random-access迭代器,可以在STL算法中使用。 你可以查看向量实现;你很可能会发现 vector<whatever>::iterator 是一个 whatever *

这并不使数组成为有效的STL容器,但它确实使指针成为有效的STL迭代器。

原作者:
0 0

是否允许使用标准的STL函数?

是的

如果是的话,像数组这样的古老结构如何适应模板化迭代器,容器和函数的宏大STL计划?

迭代器的语义与指针相似。

同样,在这种用法中,程序员应该注意的是?

我更喜欢下一个用法:

int a[] = {9, 8, 7};
const size_t a_size = lengthof( a );
cerr <<"Sum:" <<accumulate( a, a + a_size, 0, plus<int>()) <<endl;

或者使用 boost::array 更安全更安全:

boost::array <int, 3> a = { 9, 8, 7 };
cerr <<"Sum:" <<accumulate( a.begin(), a.end(), 0, plus<int>()) <<endl;
原作者:
0 0

不要使用数组,然后担心将它们传递给STL函数( 可以调用什么'向前兼容',因此是易碎的),如果你需要使用数组,那么你应该使用 std::vector 并使用它的( 稳定可靠) 向后兼容性。

所以代码变成:

#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
int main()
{
 vector<int> a(3);
 a[0] = 9;
 a[1] = 8;
 a[2] = 7;
 cerr <<"Sum:" <<accumulate(a.begin(), a.end(), 0, plus<int>()) <<endl;
 return 0;
}

如果你需要通过'一个'到一个C API,你可以这么做,多亏了向量的二进制兼容性。

原作者:
0 0

评论 mykola回答:

数组不是指针,即使它们很容易衰变为指针。 编译器对数组的信息多于容器上的信息:

namespace array {
 template <typename T, int N>
 size_t size( T (&a)[N] ) {
 return N;
 }
 template <typename T, int N>
 T* begin( T (&a)[N] ) {
 return &a[0];
 }
 template <typename T, int N>
 T* end( T (&a)[N] ) {
 return &a[N];
 }
}
int main()
{
 int theArray[] = { 1, 2, 3, 4 };
 std::cout <<array::size( theArray ) <<std::endl;//will print 4
 std::cout 
 <<std::accumulate( array::begin( theArray ), array::end( theArray ), 0, std::plus<int>() )
 <<std::endl;//will print 10
}

当你无法询问数组的大小时,编译器将在调用给定模板时解析它。

现在,如果调用一个带有 int a[] ( 注意,没有大小)的函数,这就类似于定义一个 int* 参数,并且大小信息在路径中丢失。 编译器将无法在函数内确定数组的大小: 数组已经衰变为指针。

if 而另一方面, 将参数定义为 int a[10],然后信息丢失 ,但你将无法用不同大小的数组调用函数。 这与C 版本完全不同,至少在 [*] 最近还没有检查之前。 在C 中,编译器将忽略参数中的数字,而签名将等同于以前的版本。

@litb: 你是对的,我做了这个测试,但它有一个对数组的引用,而不是数组。 感谢你的指点。

dribeas@golden:array_size$ cat test.cpp 
void f( int (&x)[10] ) {}
int main()
{
 int array[20];
 f( array );//invalid initialization of reference of type 'int (&)[10]' from...
}
原作者:
0 0

是,这是目的。 迭代器可以作为指针实现,因此你可以使用指针作为迭代器。

原作者:
0 0

boost::array ( 为传统的数组,一个简单的模板化包装器也定义 STL-compatible迭代器类型和 begin()/end() 等等)的介绍包含了一些有趣的讨论它们与STL的兼容性。

原作者:
0 0

指针模型次要迭代器,和来自数组模型随机访问迭代器的指针。 是的,这是完全合法的。

如果你对每种( T ) L 算法的用法约束感兴趣,请熟悉迭代器模型

原作者:
0 0

作为 int,[] 可以当作指针对待。 在 C++ 指针中可以增加,然后指向下一个元素。 指针可以被比较,指针可以用作迭代器。

在标准 24.1节中指出了迭代器的需求。 和指针可以满足它们。下面是一些

所有我支持的迭代器

作为指向数组的常规指针,可以保证指针值指向数组的最后一个元素,因此对于任何迭代器类型,都有一个迭代器值,它指向对应于对应容器的最后一个元素。

原作者:
...