Всегда предпочитайте std :: string (ptr, size), а не std :: string (first, last), если это возможно? - PullRequest
2 голосов
/ 17 апреля 2020

Рассмотрим:

#include <string>
#include <string_view>

using namespace std;

string sv2s_1(string_view sv)
{
    return string(sv.data(), sv.size());
}

string sv2s_2(string_view sv)
{
    return string(sv.begin(), sv.end());
}

В sv2s_1, string необходимо выделить внутренний буфер не более одного раза.

В sv2s_2, string не знает насколько велик должен быть внутренний буфер, поэтому он должен * p sh возвращать символы один за другим и может перераспределять и копировать внутренний буфер много раз.

При условии, что first и last являются итераторы произвольного доступа , string(first, last) могут использовать last - first для быстрого получения размера своего внутреннего буфера, поэтому производительность равна string(ptr, size).

Вопрос: Если first и last являются итераторами произвольного доступа,

Гарантирует ли стандарт C ++ string(first, last) эквивалентно string(ptr, size) с точки зрения производительности?

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

Я не вижу такого требования в стандарте. Стандарт говорит , что X(i, j) создает контейнер последовательности, равный диапазону [i, j), и что сложность выражения зависит от последовательности.

Рассматривая конкретную реализацию, libstdc++ предварительно вычисляет размер диапазона для итераторов прямого, двунаправленного и произвольного доступа:

template<typename InIterator>
void basic_string<CharT, Traits, Alloc>::
_M_construct(InIterator beg, InIterator end, std::forward_iterator_tag) {
    // ...
    size_type dnew = static_cast<size_type>(std::distance(beg, end));
    // ...
}

Обратите внимание, что std::bidirectional_iterator_tag и std::random_access_iterator_tag получены из std::forward_iterator_tag, и может быть неявно преобразован в него, так что эта перегрузка _M_construct вызывается для итераторов прямого, двунаправленного и произвольного доступа (и смежных итераторов в C ++ 20).

2 голосов
/ 17 апреля 2020

std :: basic_string's do c гарантирует линейную сложность для обоих следующих конструкторов:

constexpr basic_string( const CharT* s,
                        size_type count,
                        const Allocator& alloc = Allocator() ); // (4)

template< class InputIt >
constexpr basic_string( InputIt first, InputIt last,
                        const Allocator& alloc = Allocator() ); // (6)

Производительность не гарантируется, и ни один из них не должен быть реализован с использованием другого .

Примечание. Конструктор (6), принимающий итераторы, принимает InputIterator, а не RandomIterator (даже если реализация может отправлять данные по категории итераторов).

...