Я конвертирую код 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++, учитывая, что я использую интеллектуальный указатель? Правильно ли мое преобразование выше?
Я также думаю, что использование std::vector<Matrix> поможет; тогда вы можете использовать std::copy и т. д., не беспокоясь о sizeof(Matrix)
Хм, я подумал, раз уж так было MATRIX* matrix = NULL;, то мне следует использовать умный указатель. А если MATRIX matrix, то я буду использовать vector. Это неправильно? И я должен просто использовать вектор? Если мне действительно нужно использовать make_unique, есть предложения?
да, это неверно, вектор хранит свои элементы в куче, поэтому это идеальная замена для MATRIX* matrix, для элементов, выделенных в стеке, эквивалентом будет std::array
memset() будет иметь неопределенное поведение, если MATRIX не является тривиально копируемым типом. Это исключает, среди прочего, наличие любого нетривиального конструктора, нетривиального деструктора, любых виртуальных функций или любых виртуальных баз. Для получения дополнительной информации см. en.cppreference.com/w/cpp/named_req/TriviallyCopyable.
Попробуйте вместо этого использовать std::vector или std::array.
afaik std::make_unique<MATRIX[]>(256); для тех случаев, когда вы не можете использовать std;:vector по какой-то причине, когда вы можете, вы должны использовать его
Забудьте о memset. Вам это не нужно. Всегда.





vector<MATRIX> решит многие проблемы.new не возвращает ноль, а выдает. Следовательно, проверка нуля не имеет никакого эффекта (если не используется nothrow).MATRIX, который будет инициализировать все члены MATRIX. Вы можете иметь (или не допустить) конструкторы копирования/перемещения/операторы присваивания. Рассмотрите возможность использования =default и =delete со специальными функциями-членами.memcpy и т. д. могут испортить состояние некоторых не-членов POD в типе MATRIX (например, std::string, std::vector). Такое неопределенное поведение трудно обнаружить, поэтому не используйте функции памяти*.это не просто "может испортить", а афаик это УБ
да. Я просто сделал это простым.
Спасибо за предложения! На всякий случай, если я не могу использовать вектор, любое другое предложение, как превратить memset в 0 в код C++? Мне разрешено изменять только эту часть кода, поэтому я не уверен, могу ли я вообще изменить класс MATRIX.
Если memset to MATRIX вызывается/используется во многих местах, я бы предложил использовать вспомогательную функцию. Скажем, ResetMatrix(MATRIX&), который вызовет memset любой другой функции. Вы можете улучшить эту функцию, поместить утверждения во время выполнения, написать модульный тест поверх нее и т. д.
I skipped the first
memsetsince I believe I do not need it anymore for smart pointers.
Вы правы, что это не нужно, но причина того, что это не нужно, именно в том, что вы использовали std::make_unique, значение которого инициализирует массив; не потому, что вы используете умные указатели. Это предполагает, что инициализация необходима в первую очередь. Похоже, это не так, поскольку содержимое вот-вот будет заполнено функцией.
Учтите, что std::memset и std::memcpy ведут себя корректно, только если тип (в данном случае Matrix) легко копируется. Если это не так, вы должны использовать std::fill_n (или std::fill) и std::copy соответственно. Что можно использовать, если тип также тривиально копируется, поэтому вы можете использовать их в любом случае.
But the second memset I believe is needed (since new values will be saved).
Подобно первому std::memset, непонятно, почему вы думаете, что нужен второй std::memset (будь то в C или C++). Если новые значения будут записаны поверх массива, то какой эффект имеет std::memset?
So how do I write that in C++ and considering that I am using a smart pointer?
Вы можете std::memset массив, на который указывает умный указатель, вот так:
std::memset(matrix.get(), 0, 256*sizeof(decltype(*matrix)));
Или используя std::fill_n вместо этого:
std::fill_n(matrix.get(), 256, MATRIX{});
Hmm my thought was since it was
MATRIX* matrix = NULL;then I should use a smart pointer.
std::vector — это контейнер RAII, представляющий собой динамический массив. Вы динамически выделяете массив. std::vector подходит.
Преобразование C в C++ — это не просто замена простых указателей-владельцев интеллектуальными указателями. Еще одна вещь, которую нужно сделать, это заменить пользовательские повторные реализации типичных структур данных и алгоритмов стандартными, предоставляемыми стандартной библиотекой.
Спасибо! Это многое для меня проясняет. Спасибо!
Я думаю, что std::fill_n лучшая альтернатива в таких ситуациях.
Была ли причина использовать
make_unique<MATRIX[]>вместоvector<MATRIX>? Ответ на это может повлиять на ответ на ваш вопрос.