неинициализированный ход в std :: vector - PullRequest
4 голосов
/ 11 января 2012

Я использую Visual Studio 2010 и его реализация stl из dinkumware

Я заметил, что когда внутренний буфер вектора растет, вызывается _Uninitialized_move.что очень похоже на std :: uninitialized_copy.

  1. для скалярного типа, в конечном итоге он перенаправляет вызов memmove
  2. для нескалярного типа, он вызывает конструктор копирования содержащегося типа.

Я знаю, что для нескалярного типа побитовое копирование небезопасно, но я запутался в этом случае, потому что старые объекты будут уничтожены очень скоро.похоже, что побитовое копирование для всех типов безопасно, и поэтому нам нужен только свободный необработанный буфер после _Uninitialized_move.это сэкономит массу конструктора и деструктора копирования для нетривиальных объектов.

так, безопасно ли просто перемещать содержимое для нескалярного типа?

Ответы [ 3 ]

4 голосов
/ 11 января 2012

Если вы абсолютно уверены, что объекты, которые вы перемещаете, не имеют указателей друг на друга (включая подобъекты) - тогда просто перемещайте содержимое - это нормально. Однако вы не можете знать это, если вы не знаете, как тип разработан внутри. Единственным исключением является то, что если тип не больше указателя (sizeof(Type) <= sizeof( void* )), то вряд ли у него есть указатели на объекты в одном контейнере, поэтому обычно его можно просто переместить.

4 голосов
/ 11 января 2012

В C ++ 11 есть много характеристик, позволяющих узнать, безопасно ли выполнять битовые операции.

В вашем случае, я думаю, вам следует использовать std::is_trivially_move_constructible<T>,Эти черты реализованы с использованием встроенных функций компилятора (непереносимых, поэтому он находится в стандартной библиотеке), но сами они переносимы.

Поэтому код должен быть похож на:

template <typename T>
void move_to(T* storage, T* begin, T* end) {
  if (std::is_trivially_move_constructible<T>::value) {
    memmove(storage, begin, (end - begin) * sizeof(T));
  } else {
    for (; begin != end; ++begin, ++storage) {
      new (storage) T(std::move(*begin));
    }
  }
}

И компилятор оптимизирует if во время компиляции в зависимости от того, является ли тип тривиально перемещаемым, конструктивным или нет, и покидает только интересную ветвь.

1 голос
/ 11 января 2012

Нет. Если они имеют указатели друг на друга, то простой побитовый ход сделает их недействительными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...