C++ с использованием массива без вызова конструктора

Моя задача - создать массив типов шаблонов без вызова конструктора T (шаблон). После этого я хочу переместить одно значение в этот массив из другого с помощью std:: move. Как я могу сделать это в C++? Вот мой код:

void *temp = malloc((end-begin) * sizeof(T));
for (unsigned int i = begin; i < end; ++i){
    temp[i] = std::move(array[i]);
}

Но это не работа. Компилятор говорит следующее: Индекс указателя на неполный тип 'void'.

4 ответа

Решение

Массив void не имеет смысла. void является неполным типом (и не имеет размера), поэтому temp[i] генерирует ошибку, которую вы видите.

Чтобы достичь того, что вы хотите сделать, почему бы не использовать std::vector и вставлять в него предметы по мере их появления?

std::vector<T> temp;
for (unsigned int i = begin; i < end; ++i){
    temp.push_back(std::move(array[i]));
}

Если вы действительно хотите сделать это вручную, вы ищете новое место размещения. Сначала вы выделяете "сырой буфер" unsigned chars:

unsigned char* buf = new unsigned char(end-begin);

или же:

auto buf = std::make_unique<unsigned char[]>(end-begin);

а потом ты пишешь такие вещи, как new (buf) T, new (buf+sizeof(T)) T, new (buf+2*sizeof(T)) T "поместить" ваши объекты в это пространство памяти.

Проблема в том, что в приведенном выше примере я полностью проигнорировал требования выравнивания, что опасно.

Таким образом, вместо того, чтобы реплицировать, какие пулы памяти и std::vector делай, просто используй std::vector!

std::vector<T> vec;
vec.reserve(end-begin);
for (unsigned int i = begin; i < end; ++i){
   vec.push_back(std::move(array[i]);
}

и вы сделали.

Как указывают другие void не имеет определенного размера, так void* не может быть проиндексирован как массив.

Где же temp[1] начать?

Наивное исправление:

T *temp = std::malloc((end-begin) * sizeof(T));

Так же плохо, когда используется в сочетании с:

temp[i] = std::move(array[i]);

Этот код будет вызывать оператор присваивания, и, если нетривиально, произойдет сбой при работе с мусором, который находится в temp[i], Например, если назначение явно или неявно отменяет выделение ресурсов в цели назначения, оно будет работать с неинициализированным temp[i] и потерпеть неудачу.

Если (ЕСЛИ!) Вы сделали это, правильный код будет:

std::memcpy(temp+i*sizeof(i),array[I],sizeof(T));

Эта строка кода по существу предполагает, что T является тривиально копируемым типом.

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

Так что рекомендуемый код (используя for цикл) это:

T* temp= new T[end-being];
for(unsigned int i=begin;i<end;++i){
    temp[i-begin]=array[i];
}

Примечание: этот код также исправляет ошибку в исходном коде, которая ломается, когда begin!=0, Код, похоже, копирует подраздел из середины array к началу temp но забывает начать с индекса 0 из temp,

Но рекомендуемый подход C++ к такому копированию:

T* temp= new T[end-being];
std::copy(array+begin,array+end,temp);

Хорошие реализации будут определять и использовать любые объемные операции с памятью, где это возможно. Так что неявно это должно привести к std::memmove(temp,array,(end-begin)*sizeof(T)); если действительный.

Единственный последний поворот, который компилятор может не распознать, это то, что потенциально немного более эффективный

std::memcpy(temp,array,(end-begin)*sizeof(T));

На самом деле действительно в этом случае, потому что мы знаем temp не может пересекаться с array (не говоря уже о копируемом диапазоне).

Сноска. Как отмечалось в комментариях, самый обычный подход C++ заключается в использовании std::vector который обычно можно предположить, что он использует эти оптимизации за кулисами. Однако, если по какой-то причине реорганизация приложения невозможна или нежелательна, этот ответ предоставляет действительный эффективный способ переписать предоставленный код.

Пытаться

T *temp = (T*) malloc((end-begin) * sizeof(T));
Другие вопросы по тегам