Spec-Zone.ru › C++

std::vector<T,Allocator>::reserve

void reserve( size_type new_cap );
(до C++20)
constexpr void reserve( size_type new_cap );
(с C++20)

Увеличивает емкость вектора (общее количество элементов, которое вектор может содержать без необходимости перераспределения) до значения, большего или равного new_cap. Если new_cap больше текущей capacity(), выделяется новая память, в противном случае функция ничего не делает.

reserve() не изменяет размер вектора.

Если new_cap больше capacity(), все итераторы, включая end() итератор, а также все ссылки на элементы, становятся недействительными. В противном случае итераторы и ссылки не становятся недействительными.

После вызова reserve(), вставки не будут вызывать перераспределение, если только вставка не сделает размер вектора больше значения capacity().

Параметры

new_cap - новая емкость вектора, в количестве элементов
Требования к типу
- T должен удовлетворять требованиям MoveInsertable в *this. (с C++11)

Возвращаемое значение

(ничего)

Исключения

  • std::length_error если new_cap > max_size().
  • Любое исключение, брошенное Allocator::allocate() (обычно std::bad_alloc).

Если брошено исключение, функция не имеет эффекта (сильная гарантия исключений).

Если перемещающий конструктор T не является noexcept, а T не является CopyInsertable в *this, вектор будет использовать перемещающий конструктор, который может генерировать исключение. Если он бросит исключение, гарантия исключения теряется, а последствия не определены.

(с C++11)

Сложность

Максимум линейная по size() контейнера.

Примечания

Правильное использование reserve() может предотвратить ненужные перераспределения, но ненадлежащее использование reserve() (например, вызов перед каждым вызовом push_back()) может фактически увеличить количество перераспределений (заставляя емкость расти линейно, а не экспоненциально) и привести к увеличению вычислительной сложности и снижению производительности. Например, функция, которая получает произвольный вектор по ссылке и добавляет в него элементы, обычно не должна вызывать reserve() для вектора, так как она не знает особенностей использования вектора.

При вставке диапазона версия insert() для диапазона обычно предпочтительнее, так как она сохраняет правильное поведение роста емкости, в отличие от reserve() в сочетании с рядом вызовов push_back().

reserve() не может использоваться для уменьшения емкости контейнера; для этой цели предоставляется shrink_to_fit().

Пример

#include <cstddef>
#include <iostream>
#include <new>
#include <vector>
 
// minimal C++11 allocator with debug output
template<class Tp>
struct NAlloc
{
    typedef Tp value_type;
 
    NAlloc() = default;
    template<class T>
    NAlloc(const NAlloc<T>&) {}
 
    Tp* allocate(std::size_t n)
    {
        n *= sizeof(Tp);
        Tp* p = static_cast<Tp*>(::operator new(n));
        std::cout << "allocating " << n << " bytes @ " << p << '\n';
        return p;
    }
 
    void deallocate(Tp* p, std::size_t n)
    {
        std::cout << "deallocating " << n * sizeof *p << " bytes @ " << p << "\n\n";
        ::operator delete(p);
    }
};
 
template<class T, class U>
bool operator==(const NAlloc<T>&, const NAlloc<U>&) { return true; }
 
template<class T, class U>
bool operator!=(const NAlloc<T>&, const NAlloc<U>&) { return false; }
 
int main()
{
    constexpr int max_elements = 32;
 
    std::cout << "using reserve: \n";
    {
        std::vector<int, NAlloc<int>> v1;
        v1.reserve(max_elements); // reserves at least max_elements * sizeof(int) bytes
 
        for (int n = 0; n < max_elements; ++n)
            v1.push_back(n);
    }
 
    std::cout << "not using reserve: \n";
    {
        std::vector<int, NAlloc<int>> v1;
 
        for (int n = 0; n < max_elements; ++n)
        {
            if (v1.size() == v1.capacity())
                std::cout << "size() == capacity() == " << v1.size() << '\n';
            v1.push_back(n);
        }
    }
}

Возможный вывод:

using reserve: 
allocating 128 bytes @ 0xa6f840
deallocating 128 bytes @ 0xa6f840
 
not using reserve: 
size() == capacity() == 0
allocating 4 bytes @ 0xa6f840
 
size() == capacity() == 1
allocating 8 bytes @ 0xa6f860
deallocating 4 bytes @ 0xa6f840
 
size() == capacity() == 2
allocating 16 bytes @ 0xa6f840
deallocating 8 bytes @ 0xa6f860
 
size() == capacity() == 4
allocating 32 bytes @ 0xa6f880
deallocating 16 bytes @ 0xa6f840
 
size() == capacity() == 8
allocating 64 bytes @ 0xa6f8b0
deallocating 32 bytes @ 0xa6f880
 
size() == capacity() == 16
allocating 128 bytes @ 0xa6f900
deallocating 64 bytes @ 0xa6f8b0
 
deallocating 128 bytes @ 0xa6f900

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение, опубликованное Правильное поведение
LWG 329 C++98 перераспределение может быть вызвано, если вставка
делает размер вектора больше размера,
указанного в последнем вызове reserve()
вызывается только если размер
вектора становится
больше capacity()
LWG 2033 C++11 T не было необходимо требовать MoveInsertable требование выполняется

См. также

capacity
возвращает количество элементов, которое может храниться в текущем выделенном хранилище
(публичный член-функция)
max_size
возвращает максимальное возможное количество элементов
(публичный член-функция)
resize
изменяет количество хранимых элементов
(публичный член-функция)
shrink_to_fit
(DR*)
уменьшает использование памяти, освобождая неиспользуемую память
(публичный член-функция)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/container/vector/reserve

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API