2016-11-09 7 views
2

Я оказался в ситуации, когда мне бы хотелось иметь аналог unique_ptrrelease() для std::vector<>. Например:Почему std :: vector не имеет метода выпуска?

std::vector<int> v(SOME_SIZE); 

//.. performing operations on v 

int* data = v.release(); // v.size() is now 0 and the ownership of the internal array is released 
functionUsingAndInternallyDeletingRowPointer(data); 

Есть ли особая причина, почему такая возможность не предоставляется? Может ли это наложить какое-то ограничение на внутреннюю реализацию std::vector?

Или есть способ достичь этого, что я смущающе не хватает?

+0

Зачем? Если вы думаете, что это должно быть так, возможно, лоббирование комитета C++. Имейте в виду, что они обычно выступают против добавления бессмысленных излишеств в контейнеры для ядра. Почему бы просто не удалить и воссоздать объект 'std :: vector'? Я думаю, вы найдете реализацию 'release', потому что это чрезвычайно нетривиально. – tadman

+0

Ваш пример слишком упрощен. Как вы узнаете, какие деструкторы позвонить? Как бы вы нашли правильный распределитель? –

+0

@ Kerrek SB Да, я думал об этом виде проблематики, но я точно не вижу смысла. Уничтожает дескриптор 'std :: vector' таким образом, что простой' delete [] 'не сможет? –

ответ

1

Может, что наложить некоторые ограничения на станд :: вектора внутренней реализации?

Вот некоторые примеры того, что позволяет это будет противоречить:

  • Запрещая особых случаев, лежащая в основе выделения памяти не может быть получено new T[], ни уничтожены delete[], так как они могли бы назвать конструкторы и деструкторы в памяти, которые выделяются, но на самом деле не должны содержать объектов типа T.
  • Начало массива может фактически не быть началом распределения памяти; например вектор может хранить бухгалтерскую информацию непосредственно перед началом массива
  • vector может фактически не освобождать память при ее уничтожении; напримервместо этого распределение может происходить из пула небольших массивов, который используется для быстрого создания и уничтожения небольших векторов. (Кроме того, эти массивы могли бы все просто кусочки большего массива)
+0

Спасибо, особенно за первые ваши очки. Теперь это выглядит очевидно. –

+0

«* выделение может происходить из пула небольших массивов *« Что бы разбить гарантии на резьбу, если только тип блокирует мьютексы очень часто. –

+0

@ Никол: Э? Я не вижу, что может потребоваться синхронизация, кроме строительства, разрушения и изменения размера. Если вектор всегда откладывается на распределитель ... ну, это просто переносит проблему на другой программный компонент, который все еще должен управлять гарантиями потоковой передачи. – Hurkyl

3

functionUsingAndInternallyDeletingRowPointer

И что именно будет эта функция делать? Поскольку эта память была выделена вызовом std::allocator_traits<std::allocator<T>>::allocate, который ожидает ее удаления, вызвав std::allocator_traits<std::allocator<T>>::deallocate. Кроме того, каждый элемент vector был сконструирован с вызовом std::allocator_traits<std::allocator<T>>::construct и поэтому должен быть уничтожен вызовом std::allocator_traits<std::allocator<T>>::destruct.

Если эта функция пытается сделать delete [] на этом указателе, это не сработает. Или, по крайней мере, не требуется для работы.

Возможно, было бы разумно извлечь буфер памяти из vector и использовать его напрямую. Но это не могло быть простым указателем. Он должен был иметь распределитель вместе с ним.

+0

Спасибо, это именно то, что я интересовался. Выделение/освобождение производится в тривиальном порядке внутри 'std :: vector'. –

2

Есть две причины, я могу думать:

  1. первоначально (до C++ 11), vector была совместима с небольшой оптимизацией объектов. То есть, он мог бы указать на себя, если бы его размер был достаточно маленьким. Это было непреднамеренно отключено в C++ 11 (vector). Семантика перемещения запрещает недействительность ссылок/итераторов), но она может быть исправлена ​​в будущих стандартах. Таким образом, не было оснований для его предоставления исторически, и, надеюсь, этого не будет в будущем.
  2. распределители. Ваша функция может вызвать неопределенное поведение, если передается указатель на вектор с распределителем он не ожидал
1

Это было предложено в N4359, но оказывается, есть некоторые тонкие вопросы, что место нагрузки на вызывающем, чтобы избежать неправильного поведения (в основном связанные с для распределителей, похоже). Обсуждение трудностей и возможных альтернатив можно найти here. В конечном итоге он был отклонен органом стандартов C++. Дальнейшее обсуждение можно найти в комментариях this question и его ответах.