[英]Improving efficiency of std::copy() with back_inserter() or inserter()
back_inserter
and insert_iterator
are very handy, but they're also very inefficient! back_inserter
和insert_iterator
非常方便,但它们也非常低效!
When you're appending char
s, for example, there is a great deal of overhead for every element when you're copy
ing, when in many situations, there really doesn't need to be. 例如,当你附加
char
,当你copy
时,每个元素都会产生大量的开销,而在很多情况下,实际上并不需要。
Is there a way to make them more efficient? 有没有办法让它们更有效率?
Yes, you can define a new version of std::copy
which can hijack optimizable calls. 是的,您可以定义一个新版本的
std::copy
,它可以劫持可优化的调用。 :) :)
Below is an example (or "hack", if you prefer to see the glass half-empty) for Visual C++ and GCC. 以下是Visual C ++和GCC的示例(或“hack”,如果您希望看到半空的玻璃)。
On my personal computer (I use VC++ 2010), the code below makes calls ten times faster ! 在我的个人计算机上(我使用VC ++ 2010),下面的代码使调用快十倍 !
A benchmark for GCC's is also here, showing a 5x difference: old version against new version GCC的基准也在这里,显示了5倍的差异: 旧版本与新版本的对比
Note that this code assumes the container provides a vector
-like interface . 请注意,此代码假定容器提供了类似
vector
的接口 。
As currently written, this only works for C++11, because it uses the type_traits
header's metaprogramming capabilities to only optimize those situations in which the copy operation would stay exception-safe. 由于目前写的,这仅适用于C ++ 11,因为它使用了
type_traits
头的元编程功能, 仅优化那些在复制操作将保持异常安全的情况。
If you don't need the exception safety (though you should think twice before actually doing this), or if you have another way of checking for such data types, then you can change 如果您不需要异常安全(尽管您在实际执行此操作之前应该三思而行),或者如果您有其他方法来检查此类数据类型,那么您可以更改
typename enable_if<..., typename insert_iterator<C> >::type
to: 至:
insert_iterator<C>
and the rest of the code should work for C++03 as well. 其余的代码也适用于C ++ 03。
namespace std
{
template<class FwdIt, class C>
back_insert_iterator<C> copy(
FwdIt begin, FwdIt end, back_insert_iterator<C> it,
forward_iterator_tag * =
static_cast<typename iterator_traits<FwdIt>::iterator_category *>(0))
{
struct It : public back_insert_iterator<C>
{
using back_insert_iterator<C>::container;
static C &deref(C &c) { return c; }
static C &deref(C *c) { return *c; }
};
copy(begin, end, inserter(It::deref(static_cast<It &>(it).container),
It::deref(static_cast<It &>(it).container).end()));
return it;
}
template<class FwdIt, class C>
typename enable_if< // Only do this if it would be exception-safe!
is_nothrow_copy_constructible<typename C::value_type>::value &&
is_nothrow_copy_assignable<typename C::value_type>::value,
insert_iterator<C>
>::type copy(
FwdIt const &begin, FwdIt const &end,
insert_iterator<C> output,
forward_iterator_tag * = // only forward iterators
static_cast<typename iterator_traits<FwdIt>::iterator_category *>(0))
{
struct It : public insert_iterator<C>
{
using insert_iterator<C>::container; // protected -> public
using insert_iterator<C>::iter; // protected -> public
static C &deref(C &c) { return c; }
static C &deref(C *c) { return *c; }
};
It &it(static_cast<It &>(output));
typename C::iterator it_iter_end(It::deref(it.container).end());
{
// Convert iterators to offsets
typename C::size_type const iter_end_off =
std::distance(It::deref(it.container).begin(), it_iter_end);
typename iterator_traits<typename C::iterator>::difference_type off
= std::distance(It::deref(it.container).begin(), it.iter);
// Resize container
It::deref(it.container).resize(
It::deref(it.container).size() +
static_cast<typename C::size_type>(std::distance(begin, end)));
// Renormalize, in case invalidated
it.iter = It::deref(it.container).begin();
std::advance(it.iter, off);
it_iter_end = It::deref(it.container).begin();
std::advance(it_iter_end, iter_end_off);
}
typename C::iterator result
= copy_backward(it.iter, it_iter_end, It::deref(it.container).end());
copy_backward(begin, end, result);
return inserter(It::deref(it.container), result);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.