2

I have this function:

void foo(const double *const *matrix, unsigned num_rows, unsigned num_columns){
    //matrix[0][0] = 5; // ERROR: expression must be a modifiable lvalue
    for (unsigned i = 0; i < num_rows; i++) delete matrix[i];
    delete matrix;
}

...wherein the function cannot change the values at any given index in the matrix, yet it is still able to delete the matrix or any of its rows. Is there a way to pass in a 2D matrix and guarantee that it will not be altered in any way?

Edit: it doesn't look like there's a way to do this, so I'll probably switch to using vectors.

user3076399
  • 121
  • 3
  • 13
  • I'd start out to dump raw arrays for doing such, but using a `std::array,num_cols>` or a `std::vector>` – πάντα ῥεῖ Dec 27 '16 at 20:21
  • 1
    See '[1D or 2D array, what's faster?](http://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster)' about why you most likely do not want to have 2 dimensional dynamic arrays of arrays or `vector>` for (dense) matrices anyway. My answer has a small matrix example class. (You can of course just have `vector` and handle the mapping for yourself.) – Pixelchemist Dec 27 '16 at 20:29
  • Cool tip, Pixelchemist. But if I know the size of my matrix and know it won't ever change, I think vectors of vectors will be much easier to visualize for both myself as a developer and for the users. The program takes (static) images as input and outputs some data about it. I'd rather have the user build a 2D vector of vectors than them having to learn about the 1D approach. Do you agree? – user3076399 Dec 27 '16 at 20:36
  • 1
    @user3076399: I'd rather have a class with `Matrix m(20,20);` and something like `m[0][0] = 1.0;` or `m(0, 0) = 1.0;` Because safely using the vector of vectors requires size/bounds checks for every sub-vector etc. – Pixelchemist Dec 27 '16 at 20:42
  • @Pixelchemist Every subvector will always be the same length, since the matrix is square. – user3076399 Dec 27 '16 at 21:07
  • Write a matrix class (or find an existing one). There's no excuse passing around C-style raw pointers like that, when writing C++ today. – hyde Dec 27 '16 at 21:08
  • @user3076399: Yeah but you'l have to check/assert it anyway - even if it should be properly sized you locally don't get any guarantee other than checking. If you have a class that provides that guarantee you can avoid to check every row. – Pixelchemist Dec 27 '16 at 21:20

2 Answers2

1

No.

delete can be called on a pointer even if it's passed as a const & or even declared const because the pointer is not going to be changed.

There is also no way to prevent someone from doing

unsigned char *p = (unsigned char *)your_precious_data_pointer;
*p = 42;

Get over it.

Const correctness was designed to detect accidental mistakes, not for preventing intentional actions by programmers. It's not about security.

It can even be debated if it's a good tool for preventing accidental mistakes.

6502
  • 112,025
  • 15
  • 165
  • 265
0

No. But you shouldn't use new, delete and raw owning pointers anyway, and certainly not delete arbitrary pointers.

If that isn't enough to switch to smart pointers and containers... You are actually triggering undefined behaviour by deleteing something which has visibly been allocated with new[]. That's another mistake to look out for with raw owning pointers.

On a side note, this is not a 2D array, but an array of pointers.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Why not? What should I use instead? – user3076399 Dec 27 '16 at 20:22
  • @juanchopanza it is. I'm giving myself the leeway not to type out "pointer to the first element of an array of pointers to the first element of more arrays of `double`s". – Quentin Dec 27 '16 at 20:26
  • @Quentin Yeah, but we can't even know it is a pointer to the first element of an array. As far as the function is concerned, the parameter is a pointer. – juanchopanza Dec 27 '16 at 20:27
  • @juanchopanza trust in the caller, so that `for`-loop doesn't just shoot off the end of the array into UB land. Raw pointers are all about trust after all. – Quentin Dec 27 '16 at 20:29
  • @user3076399 you should have a look at `std::vector` and `std::unique_ptr`. – Quentin Dec 27 '16 at 20:33
  • @Quentin Maybe if OP understands that pointers are not arrays and pointers to pointers are not matrices, they'll understand why they can't get the desired "immutability". – juanchopanza Dec 27 '16 at 20:34
  • @juanchopanza to be fair I don't see how that is relevant. A true dynamically allocated 2D array can be `delete[]`d all the same, be it `const` or not. That's just how `delete` works. – Quentin Dec 27 '16 at 20:35