Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memset for Unique Pointers

I am converting a C code to C++.

There is matrix pointer:

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

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

Then it was filled on a different method:

fillUpMatrix(matrix);

And in fillUpMatrix():

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

And later on memset was called for the pointer since it will be filled with a different set of values:

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

So what I did was:

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

I skipped the first memset since I believe I do not need it anymore for smart pointers. But the second memset I believe is needed (since new values will be saved). So how do I write that in C++ and considering that I am using a smart pointer? Is my conversion above correct?

like image 954
kzaiwo Avatar asked Jun 26 '19 10:06

kzaiwo


2 Answers

I skipped the first memset since I believe I do not need it anymore for smart pointers.

You're right that it isn't needed, but the reason for not needing it specifically that you used std::make_unique, which value initialises the array; not because you're using smart pointers. That is assuming initialisation is needed in the first place. That doesn't appear to be the case, since the content is about to be filled in a function.

Do take into consideration that std::memset and std::memcpy behave correctly only if the type (Matrix in this case) is trivially copyable. If that is not the case, you must use std::fill_n (or std::fill) and std::copy respectively. Which can be used if the type is trivially copyable too, so you might as well use them in any case.

But the second memset I believe is needed (since new values will be saved).

Similar to the first std::memset, It's unclear why you think that a second std::memset is needed (whether in C or C++). If the new values are going to be written over the array, then what effect does the std::memset have?

So how do I write that in C++ and considering that I am using a smart pointer?

You can std::memset an array pointed by smart pointer like this:

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

Or using std::fill_n instead:

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 is a RAII container that represents a dynamic array. You're dynamically allocating an array. std::vector is appropriate.

Converting C to C++ is not just about replacing bare owning pointers with smart pointers. Another thing to do is to replace custom re-implementations of typical data structures and algorithms with the standard ones provided by the standard library.

like image 61
eerorika Avatar answered Nov 02 '22 20:11

eerorika


  • Using a vector<MATRIX> would solve many problems.
  • new doesn't return null, but throws. Hence null check has no effect (unless nothrow is used).
  • You're mixing raw pointer approach with newer smart-pointer, vector based approach. You shouldn't be using any raw memory manipulation functions in the latest C++ code.
  • Instead, have a constructor in the MATRIX class which would initialize all members of MATRIX. You can have (or prevent) copy/move constructors/assignment operators. Consider using =default and =delete with special member functions.
  • memcpy etc may corrupt the state of some non-POD members in MATRIX type (like std::string, std::vector). Such undefined-behaviours are hard to detect, hence don't use any mem* functions.
like image 27
Ajay Avatar answered Nov 02 '22 22:11

Ajay