Повышение эффективности std :: copy () с помощью back_inserter () или insertter ()

back_inserter а также insert_iterator очень удобны, но они также очень неэффективны!

Когда вы добавляете chars, например, есть много накладных расходов для каждого элемента, когда вы copyОднако, когда во многих ситуациях это действительно не нужно.

Есть ли способ сделать их более эффективными?

4

Решение

Да, вы можете определить новую версию std::copy который может похитить оптимизированные звонки. 🙂

Ниже приведен пример (или «хак», если вы предпочитаете, чтобы стекло было полупустым) для Visual C ++ и GCC.

На моем персональном компьютере (я использую VC ++ 2010), код ниже делает звонки десять раз Быстрее!
Здесь также есть тест для GCC, показывающий разницу в 5 раз: старая версия против новая версия

Но до вы используете его:

Обратите внимание, что этот код предполагает, что контейнер обеспечивает vectorинтерфейс.

Как написано в настоящее время, это работает только для C ++ 11, потому что он использует type_traits возможности метапрограммирования заголовка только оптимизировать те ситуации, в которых операция копирования останется безопасной для исключения.

Если вам не нужна безопасность исключений (хотя вы должны дважды подумать, прежде чем делать это), или если у вас есть другой способ проверки таких типов данных, вы можете изменить

typename enable_if<..., typename insert_iterator<C> >::type

чтобы:

insert_iterator<C>

и остальная часть кода должна работать для 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);
}
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]