WedX - журнал о программировании и компьютерных науках

Емкость копируется в вектор?

Возьмите следующий код:

std::vector<int> a;
a.reserve(65536);
std::vector<int> b(a);  //NOTE: b is constructed from a

a.reserve(65536); // no reallocation
b.reserve(65536);

Емкость копируется? Будет ли перераспределение на последней строке? В стандарте что-то об этом сказано или умалчивается?

05.06.2016


Ответы:


1

Емкость копируется?

На практике нет. Я тестировал его онлайн в Clang и GCC, а также MSVC, и ни один из них не копирует емкость.

Будет ли перераспределение на последней строке?

Если емкость меньше аргумента для резервирования (т. е. она не копируется), то да.

В стандарте что-то об этом сказано или умалчивается?

В vector.cons нет определений конструктора копирования. Вместо этого нам нужно взглянуть на container.requirements.

X обозначает класс-контейнер, содержащий объекты типа T, a и b обозначают значения типа X, u обозначает идентификатор, r обозначает неконстантное значение типа X, а rv обозначает неконстантное значение типа X.

X u(a)

X u = a;

Требуется: T вместо CopyInsertable превращается в X (см. ниже).

сообщение: u == a

Теперь, что означает, что два контейнера равны?

a == b

== является отношением эквивалентности. equal(a.begin(), a.end(), b.begin(), b.end())

Другими словами, поскольку при сравнении не требуется, чтобы capacity было равным, нет причин копировать capacity.

05.06.2016
  • @ P0W P0W Я не вижу простого способа сослаться на прямой образец кода на rextester. 06.06.2016

  • 2

    Стандарт ничего не говорит о сохранении емкости при вызове конструктора копирования. Так что никаких гарантий по этому поводу у вас нет.

    Но вы можете сделать следующий трюк, который меняет местами состояния a и b, если вам нужно сохранить емкость только в копии:

     std::vector<int> a;
     a.reserve(65536);
     std::vector<int> b(a);
     b.swap(a); // now b has a's state
     assert(b.capacity() == 65536); 
    
    05.06.2016
  • Это просто меняет местами какой reserve вызов вызовет перераспределение. 05.06.2016
  • swap ничего не делает с распределителем, обменивает только состояние объектов. 05.06.2016
  • Итак, можете ли вы поменять местами векторы, имеющие разные распределители? Если это так, он не может просто поменять местами один фрагмент выделенной памяти. 05.06.2016
  • @JDługosz Два вектора с разными типами распределителя — это разные типы векторов, поэтому вы не можете поменять их местами. 05.06.2016
  • Так что ничего не делать с аллокаторами не имеет большого значения, поскольку они уже равны. Но тип распределителя позволяет указывать значения распределителя для каждого экземпляра, а объекты имеют один и тот же тип. 05.06.2016
  • @JDługosz своп меняет состояния только без перераспределения. Обмен можно применять к объектам, имеющим ту же специализацию, что и векторные типы. В чем проблема? 05.06.2016
  • @AnatolyS: я не уверен, что swap ничего не делает с распределителем, мне ответили только swap состоянием объектов. Если это так, то я не понимаю, о чем вы думали. Два вызова reserve, о которых я упоминал, - это те, что в примере OP. 05.06.2016
  • @AnatolyS Это неверно в С++ 11. В С++ 03 распределители, где требуется, чтобы они не сохраняли состояние, поэтому оператор swap ничего не делает с распределителями, что в некоторой степени верно. В C++11 поведение swap относительно распределителя настраивается allocator_traits<Alloc>::propagate_on_container_swap. 05.06.2016

  • 3

    Нет, емкость не гарантируется при использовании vector копии.

    Вы можете сделать это следующим образом:

    vector<int> b;
    b.reserve( a.capacity() );
    b = a;
    

    Лучше инкапсулировать в функцию.

    05.06.2016

    4

    Итак, простая проверка, подобная следующей, показывает, что емкость не скопирована:

    std::vector<int> a;
    a.reserve(65536);
    cout << "a.capacity is " << a.capacity() << endl; // prints 65536
    
    std::vector<int> b(a);  //NOTE: b is constructed from a
    cout << "b.capacity is " << b.capacity() << endl; // prints 0
    

    Я считаю, что при копировании вектора a в b емкость b устанавливается равной размеру a в большинстве компиляторов; хотя это не гарантируется.

    05.06.2016
  • Это показывает, что ваша конкретная реализация не копирует емкость. Он не говорит вам, является ли это ошибкой или нет. 05.06.2016

  • 5
    1. Как показано ниже, исходный код вектора SGI STL, operator= зарезервирует место ровно для n элементов, т. е. _M_end_of_storage = _M_start + __xlen;.
        template <class _Tp, class _Alloc>
        vector<_Tp,_Alloc>&
        vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x)
        {
          if (&__x != this) {
            const size_type __xlen = __x.size();
            if (__xlen > capacity()) {
              iterator __tmp = _M_allocate_and_copy(__xlen, __x.begin(), __x.end());
              destroy(_M_start, _M_finish);
              _M_deallocate(_M_start, _M_end_of_storage - _M_start);
              _M_start = __tmp;
              _M_end_of_storage = _M_start + __xlen;
            }
            else if (size() >= __xlen) {
              iterator __i = copy(__x.begin(), __x.end(), begin());
              destroy(__i, _M_finish);
            }
            else {
              copy(__x.begin(), __x.begin() + size(), _M_start);
              uninitialized_copy(__x.begin() + size(), __x.end(), _M_finish);
            }
            _M_finish = _M_start + __xlen;
          }
          return *this;
        }
    
    1. Как показано ниже, исходный код вектора SGI STL, векторный конструктор копирования зарезервирует место ровно для n элементов, т. е. _M_end_of_storage = _M_start + __n;.
          template <class _InputIterator>
          vector(_InputIterator __first, _InputIterator __last,
                 const allocator_type& __a = allocator_type()) : _Base(__a) {
            typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
            _M_initialize_aux(__first, __last, _Integral());
          }
    
          template <class _Integer>
          void _M_initialize_aux(_Integer __n, _Integer __value, __true_type) {
            _M_start = _M_allocate(__n);
            _M_end_of_storage = _M_start + __n;
            _M_finish = uninitialized_fill_n(_M_start, __n, __value);
          }
    
    28.05.2020
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]