Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过值传递std算法迭代器参数与通过引用传递std算法迭代器参数_C++_Templates_Stl - Fatal编程技术网

C++ 通过值传递std算法迭代器参数与通过引用传递std算法迭代器参数

C++ 通过值传递std算法迭代器参数与通过引用传递std算法迭代器参数,c++,templates,stl,C++,Templates,Stl,我想知道为什么在STL中的许多模板算法中,参数不是通过引用传递的,而是通过值传递的。以下是标题中的一个示例: 模板 类型名迭代器特征::差异类型 距离(先输入计数器,后输入计数器); 当我向这个函数传递两个迭代器时,它们被复制。我的天真想法是,最好通过常量引用传递这些迭代器,以避免复制迭代器对象: template<class InputIterator> typename iterator_traits<InputIterator>::difference_type

我想知道为什么在STL中的许多模板算法中,参数不是通过引用传递的,而是通过值传递的。以下是
标题中的一个示例:

模板
类型名迭代器特征::差异类型
距离(先输入计数器,后输入计数器);
当我向这个函数传递两个迭代器时,它们被复制。我的天真想法是,最好通过常量引用传递这些迭代器,以避免复制迭代器对象:

template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (const InputIterator &first, const InputIterator &last);
模板
类型名迭代器特征::差异类型
距离(常数输入和第一个、常数输入和最后一个);
可以说迭代器通常是非常小的对象,复制它们并不昂贵。但即便如此:便宜的拷贝也比根本不拷贝要贵

那么,在STL版本中,迭代器按值传递的原因是什么呢


谢谢大家!

对于某些便宜的复制类型,通过值传递它们实际上比通过引用传递更快。来自教程等的传统智慧指出,通过引用速度更快,但这并不一定适用于廉价的复制类型

如何通过值传递对象?您复制它,这意味着您获取该值并将其推送到堆栈中进行函数调用。你是如何通过参考传递的?将内存地址推送到堆栈中,然后被调用的函数必须获取该地址上的任何内容。现在,优化和缓存可能会起到作用,使内存获取更便宜,但您仍然不会比从堆栈中获取确切的值更便宜。在迭代器的情况下,它通常只是一个简单的指针。这是一个词长,所以很便宜的复制


另外,请注意,您建议传递一个常量引用。这意味着无论如何都必须在被调用的函数中复制它才能修改它(例如在循环中递增)。

我想到的一件事与引用中的
常量相反:使用迭代器时需要修改迭代器


另一个实现细节可能是迭代器实际上只是作为指针实现的。在大多数情况下,参考文献也是如此。如果按值传递指针,则复制它一次,但仅在需要时取消引用它。但是,如果迭代器指针本身是由引用指针传递的,那么必须首先解除对它的引用,以便访问迭代器,每次访问迭代器时都必须这样做。这是多余的。

迭代器的概念是标准的。
std
容器的迭代器通常被实现为组成单个指针的类型。对于复制成本与指针一样低的参数类型,通过引用传递参数比通过值传递要昂贵。必须先解除对对象的引用,然后才能使用对象的值。有关更多详细信息,请参阅

因为几乎所有的
std
算法都需要复制迭代器,为了获得最佳性能,迭代器的复制成本已经很低了。由于这个原因,很难找到一个迭代器,它通过值传递比通过引用传递要昂贵得多

std::distance
和许多其他算法的情况下,整个算法非常简单,调用很可能由编译器内联。如果调用是内联的,则参数是通过引用还是通过值传递并不重要。[请注意,内联函数调用与内联函数声明不同!]


如果迭代器按值传递比按引用传递更昂贵,并且函数调用没有内联,则可以为按右值引用传递迭代器设置参数。在这种罕见的情况下,性能的提高可能不值得额外的复杂性。

大多数算法修改其参数。例如,
distance
可以实现如下1:

模板
类型名迭代器特征::差异类型
距离(先输入计数器,后输入计数器){
typename迭代器_traits::差异_类型结果{};
while(first++!=last)
++结果;
返回结果;
}
显然,如果您将
first
作为
const
引用传递,则这不起作用

如果将其作为非
const
引用传递,它也不起作用,因为在大多数调用上下文中,调用方的对象无法修改(例如,如果将
container.begin()
的结果传递给函数)

当然,您仍然可以通过
const
引用,在函数中创建一个副本,然后修改它。在这一点上,我们将一无所获

<> P>与C++标准建议迭代器应该是轻量级类型,复制应该便宜,在大多数情况下,通过值传递它们更有效:

但即便如此:便宜的拷贝也比根本不拷贝要贵

不正确。您还需要复制引用(在非内联函数调用的情况下,它将作为指针实现)。然后您需要取消引用该指针,这也会增加开销。与直接副本相比,直接副本在许多情况下可能与复制指针一样便宜,并且不会产生任何取消引用开销



1当然,对于随机访问迭代器来说,真正的实现是优化的,以使其具有常数而不是线性运行时。上述实现仅用于说明。

我想到的一件事与参考中的
const
相反:迭代器在使用时需要修改。另一个实现是细节可能是迭代器实际上只是作为指针实现的,在大多数情况下引用也是如此
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (const InputIterator &first, const InputIterator &last);
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (InputIterator first, InputIterator last) {
    typename iterator_traits<InputIterator>::difference_type result{};
    while (first++ != last)
        ++result;
    return result;
}