何时使用std :: begin和std :: end而不是容器特定版本

mar*_*ark 89 c++ c++11

有没有到底应该用来代替自由函数来解释,当容器开始和特定版本的任何一般的偏好或规则std::beginstd::end

这是我的理解是,如果该函数是一个模板,其中容器类型是模板参数则std::beginstd::end应使用,即:

template<class T> void do_stuff( const T& t )
{
    std::for_each( std::begin(t), std::end(t), /* some stuff */ );
}
Run Code Online (Sandbox Code Playgroud)

在其他场景中,例如已知容器类型的标准/成员函数呢?它仍然是更好的做法是使用std::begin(cont)std::end(cont)或应容器的成员函数cont.begin()cont.end()首选?

我在假设有通过调用在性能上没有任何好处纠正cont.end()std::end(cont)

Dav*_*eas 74

自由函数版本比容器的成员函数更通用.我可能会在通用代码中使用它,其中容器的类型之前是未知的(并且可能是数组).在其余的代码中(即当容器被固定并且已知时)我可能会c.begin()因惯性而使用.我希望有关C++的新教科书可以推荐免费的功能版本(因为它永远不会更糟,有时甚至更好),但这必须赶上常用的用法.

  • 提及它的+1将是'由于惯性' (5认同)

Moo*_*ice 32

如果你看一下,比如说std::begin:

template< class C > 
auto begin( C& c ) -> decltype(c.begin());
Run Code Online (Sandbox Code Playgroud)

begin()无论如何,你看到它所做的一切都是参考.我想一个不错的编译器会使差异为零,所以我猜它归结为偏好.就个人而言,我会使用cont.begin(),cont.end()以便我不必向任何人解释:)

然而,正如Mooing Duck指出的那样,它std::begin也适用于阵列:

template< class T, size_t N > 
T* begin( T (&array)[N] );
Run Code Online (Sandbox Code Playgroud)

......所以有需要考虑的问题.如果你使用数组,我会考虑我的建议.但是,如果您不确定传递的内容是STL容器还是数组<T>,那么std::begin()就可以了.

  • 我被投票了,因为我认为这是错误的答案.它没有归结为偏好; std :: begin只为调用者提供了更大的灵活性,而不仅仅是数组. (21认同)
  • 它在数组上工作的事实是我总是使用std :: begin from template的原因. (14认同)
  • [Dig]它不仅仅适用于数组,而且使用`std :: begin()`使调用者可以根据需要对其进行专门化,例如,一个没有通常的开始/结束函数的类型,并且无法添加.我认为比使用std :: begin更好!auto beg = begin(c);`在`std :: begin()`的特化不足的情况下 - 例如部分特化 - 这将支持`begin()`的参数依赖查找. (7认同)

Jon*_*nna 10

除非某些优化被关闭以进行调试,否则使用cont.begin()(或获取指向第一个元素或其他任何内容的指针)将没有性能优势,除非有人提供了一个非常奇怪的实现!几乎所有的实现(当然还有那些带有STL的实现)都是晶圆薄的,并且在编译器的口中融化.

加号在上面的"或者其他"中:相同的代码可以在不同的集合类型中工作,无论是来自STL,还是数组,还是第三方的一些奇怪的集合,如果他们认为它提供了开始的特殊化.即使你从来没有使用它,begin() 众所周知应该有一个熟悉的好处.