#c #c 11
#c #c 11
Вопрос:
Я хочу реализовать std::end для уникального указателя. Проблема в том, что я должен получить N (количество элементов в массиве).
1.Подход к выводу типа из шаблона
template <typename T, size_t N>
T* end(const unique_ptr<T[N]> amp;arr)
{
return arr.get() N;
}
Но я получил ошибку ошибка: C2893: Не удалось специализировать шаблон функции ‘T * test::end(const std::unique_ptr> amp;)’ с [_Ty=T [N] ] Со следующими аргументами шаблона: ‘T= int’ ‘N = 0x00’
Похоже, что невозможно вывести N
2.Получаем N из распределителя. Распределитель должен знать N, чтобы правильно выполнить delete[] . Вы могли бы прочитать об этом в этой статье. Существует два подхода:
-
Чрезмерно выделите массив и поместите n чуть левее.
-
Используйте ассоциативный массив с p в качестве ключа и n в качестве значения.
Проблема в том, как получить кроссплатформенный / компилятор такого размера.
Может быть, кто-то знает лучшие подходы или знает, как заставить это работать?
Комментарии:
1. Этот код действительно работает … если вам действительно нужно
unique_ptr<T[N]>
передать вend
, а не вunique_ptr<T[]>
. Возможно, в вашем вопросе вы могли бы также показать какой-то такой же код, показывающий, как вы собираетесь вызыватьend
Ответ №1:
Если у вас есть массив размером с время выполнения, и вам нужно знать его размер без необходимости вручную вести бухгалтерский учет, тогда вам следует использовать std::vector
. Он будет управлять памятью и размером для вас.
std::unique_ptr<T[]>
это просто оболочка для необработанного указателя. Вы не можете получить размер блока, на который указывает указатель, только из указателя. Причина, по которой вы используете std::unique_ptr<T[]>
over T* foo = new T[size]
, заключается в том, что функция unique_ptr
гарантирует delete[]
, что вызывается, когда указатель выходит за пределы области видимости.
Ответ №2:
Что-то вроде этого?
template<class X>
struct sized_unique_buffer;
template<class T, std::size_t N>
struct sized_unique_buffer<T[N]>:
std::unique_ptr<T[]>
{
using std::unique_ptr<T[]>::unique_ptr;
T* begin() const { return this->get(); }
T* end() const { return *this?begin(*this) N:nullptr; }
bool empty() const { return N==0 || !*this; }
};
где мы имеем неисполненное обещание фиксированной продолжительности времени компиляции во время компиляции.
Подобный дизайн мог бы работать для динамической продолжительности выполнения.
В некоторых компиляторах количество, T
когда T
можно тривиально уничтожить, не сохраняется при вызове new T[N]
. Система вольна перераспределять и предоставлять вам буфер большего размера (т. Е. округлять до границы страницы для большого выделения или неявно сохранять размер буфера через местоположение, из которого он выделен, чтобы уменьшить накладные расходы и округлить выделения в большую сторону), поэтому размер выделения не обязательно должен точно соответствовать количеству элементов.
Для нетривиально уничтоженных T
верно, что компилятор должен знать, сколько нужно уничтожить, исходя только из указателя. Эта информация не предоставляется C .
Вы можете выполнить ручное распределение буферов и подсчета и передать это в unique_ptr
с пользовательским удалителем, даже без состояния. Это позволило бы ввести тип
unique_buffer<T[]> ptr;
где вы можете получить количество элементов при незначительных затратах времени выполнения.
Если вы вместо этого сохраните длину в deleter, вы можете получить немного больше локальности в пределах цикла (экономя пропуск кэша) за счет большего unique_buffer<T[]>
.
Выполнение этого с помощью unadulterated unique_ptr<T[]>
невозможно переносимым способом.