Memset для уникальных указателей - PullRequest
4 голосов
/ 26 июня 2019

Я конвертирую код C в C ++.

Имеется матричный указатель:

MATRIX* matrix = NULL;
matrix = new MATRIX[256];

if (matrix == NULL)
   return FAIL;
memset(matrix, 0, 256*sizeof(MATRIX));

Затем он был заполнен другим методом:

fillUpMatrix(matrix);

И в fillUpMatrix ():

memcpy(&matrix[start], &someOtherMatrix[pos], sizeof(MATRIX));

А позже для указателя был вызван memset, так как он будет заполнен другим набором значений:

memset(matrix, 0, 256*sizeof(MATRIX));

Так чтоЯ сделал следующее:

auto matrix= std::make_unique<MATRIX[]>(256);
fillUpMatrix(matrix.get());

Я пропустил первый memset, так как считаю, что он мне больше не нужен для умных указателей.Но второй memset я считаю необходимым (поскольку новые значения будут сохранены).Так как мне написать это на C ++ и учитывая, что я использую умный указатель?Правильно ли мое преобразование выше?

Ответы [ 2 ]

3 голосов
/ 26 июня 2019

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

Вы правы в том, что это не нужно, но причина, по которой он вам не нужен, в частности, вы использовали std::make_unique, значение которого инициализирует массив; не потому, что вы используете умные указатели. Это предполагает, что инициализация необходима в первую очередь. Похоже, что это не так, поскольку содержимое должно заполняться функцией.

Учтите, что std::memset и std::memcpy ведут себя корректно, только если тип (Matrix в данном случае) легко копируется. Если это не так, вы должны использовать std::fill_n (или std::fill) и std::copy соответственно. Который может быть использован, если тип также является тривиально копируемым, так что вы можете использовать их в любом случае.

Но необходим второй набор настроек (так как новые значения будут сохранены).

Как и в первом std::memset, неясно, почему вы думаете, что необходим второй std::memset (будь то в C или C ++). Если новые значения будут записаны в массив, то какой эффект имеет std::memset?

Так как мне написать это в C ++ и учитывая, что я использую умный указатель?

Вы можете std::memset массив указывать умным указателем, как это:

std::memset(matrix.get(), 0, 256*sizeof(decltype(*matrix)));

Или использовать std::fill_n вместо:

std::fill_n(matrix.get(), 256, MATRIX{});

Хмм, моя мысль была, поскольку это было MATRIX* matrix = NULL;, тогда я должен использовать умный указатель.

std::vector - это контейнер RAII, представляющий динамический массив. Вы динамически распределяете массив. std::vector подходит.

Преобразование C в C ++ - это не просто замена простых указателей-владельцев умными указателями. Другая вещь, которую нужно сделать, - это заменить пользовательские повторные реализации типичных структур данных и алгоритмов на стандартные, предоставляемые стандартной библиотекой.

1 голос
/ 26 июня 2019
  • Использование vector<MATRIX> решит многие проблемы.
  • new не возвращает ноль, но бросает. Следовательно, нулевая проверка не имеет никакого эффекта (если не используется nothrow).
  • Вы смешиваете подход с необработанным указателем с новым интеллектуальным указателем, векторным подходом. Вы не должны использовать какие-либо необработанные функции управления памятью в последнем коде C ++.
  • Вместо этого в конструкторе MATRIX имеется конструктор, который инициализирует все члены MATRIX. Вы можете иметь (или предотвращать ) копирование / перемещение конструкторов / операторов присваивания. Попробуйте использовать =default и =delete со специальными функциями-членами.
  • memcpy и т. Д. Может повредить состояние некоторых не-POD членов типа MATRIX (например, std::string, std::vector). Такое неопределенное поведение трудно обнаружить, поэтому не используйте никаких функций mem *.
...