1

I have a class with a 2D array of ints implemented as an int**. I implemented an accessor function to this 2D array as follows, returning a const int** to prevent the user from being able to edit it:

const int** Class::Access() const
{
     return pp_array;
}

But I got the compilation error "invalid conversion from int** to const int**". Why is a promotion to const not allowed here? How can I give the user access to the information without editing rights?

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
Bugalugs Nash
  • 492
  • 1
  • 6
  • 21
  • 1
    Note: your variable names cannot begin with numbers. – chris May 04 '12 at 03:45
  • Right, it doesn't actually in the code, that's just an oversight by me in generalising the names - edited out now :) – Bugalugs Nash May 04 '12 at 03:48
  • A Matrix class encapsulating a 1D vector would work really well for holding the data too. Much better than a 2D pointer array. It also eliminates confusion such as this. – chris May 04 '12 at 03:49
  • 1
    are you also getting the '...discards qualifiers...' error message? – A. K. May 04 '12 at 03:52
  • I haven't learned about vectors yet unfortunately... – Bugalugs Nash May 04 '12 at 03:54
  • @AdityaKumar - No I'm only getting the one error message – Bugalugs Nash May 04 '12 at 03:55
  • Always a good time to start. The syntax is, for the most part, identical to arrays, with better support for being passed around from function to function. They also include out-of-bounds checking if you use `at` instead of `[]`. – chris May 04 '12 at 03:55
  • This must have been covered by a prior question, it's a very common problem. – Mark Ransom May 04 '12 at 03:58
  • @Mark: Probably, but if there is an existing question, it's not tagged well. There are no other questions with `const` and `multiple-indirection`. – Ben Voigt May 04 '12 at 04:08
  • @Mark: Ok, I found one, but it's about C, and the only relevance to this case is in linked websites. – Ben Voigt May 04 '12 at 04:18

2 Answers2

6

Greyson is correct that you'll want to use const int* const*, but didn't explain why your original version failed.

Here is a demonstration of why int** is incompatible with const int**:

const int ci = 0;
const int* pci = &ci;
int* pi;
int** ppi = π
const int** ppci = ppi; // this line is the lynchpin
*ppci = pci;
*pi = 1; // modifies ci!
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • While this is correct, it does not address the reason that the int** needs to be const in this instance; The 'const'ness of the method is why returning the mutable pointers to pointers to ints is the key. – Greyson May 04 '12 at 04:01
  • @Greyson: The `const`-ness of the method makes no difference, no one is writing `pp_array = anything`. The new wording I just added is an explanation why your reasoning was totally wrong. – Ben Voigt May 04 '12 at 04:02
  • Without the `const`-ness of the method the return specification of `int const **` is fine, though. – Greyson May 04 '12 at 04:04
  • @Greyson: With a `const` method, a return specification of `int**` is still fine. I explained why. However, he wanted to return a read-only pointer, i.e. `int const **`, but `const` must be added from the outside in. Also, did you even read the warning message? – Ben Voigt May 04 '12 at 04:05
  • I'm a little confused - I see what you're saying is that int** cannot convert to const int** because it messes with the const-ness of the int being pointed to. But in your code, at what point does it say that pi points to ci? – Bugalugs Nash May 04 '12 at 04:10
  • @BugalugsNash: The second-to-last line writes into `pi` for the first time, storing `&ci` (the value inside `pci`). – Ben Voigt May 04 '12 at 04:14
  • @Greyson and Ben - to test what you're saying I removed the const from the original method and was receiving the same error - invalid conversion from int** to const int** – Bugalugs Nash May 04 '12 at 04:16
  • @BugalugsNash: I already said that the `const` on the method doesn't matter (My first comment to this answer). – Ben Voigt May 04 '12 at 04:19
  • There seemed to be an argument about it, I thought I'd let you both know what the compiler said. – Bugalugs Nash May 04 '12 at 04:31
4

I was mistaken about the constness of the method being the reason for the error. As Ben points out, the const-ness of the method is irrelavent, since that applies only to the value of the exterior pointer [to pointers to ints], which can be copied to a mutable version trivially.

In order to protect the data (which is your preferred outcome) you should make both the ints and the pointers to ints constant:

int const * const * Class::Access() const
{
   return pp_array;
}

Will work.

If you prefer to have the const in front you can also write the declaration like so:

const int * const * Class::Access() const;

but since the second const applies to the pointers, it must be placed to the right (like the const which applies to the method) of the asterisk.

Greyson
  • 3,598
  • 1
  • 21
  • 22
  • why has the const been removed from before the int? is the data pointed to still constant here? – Bugalugs Nash May 04 '12 at 03:53
  • 1
    @BugalugsNash, read it right to left. The int is still const. However, if there's nothing to the left of the const, it applies to the right. – chris May 04 '12 at 03:54
  • const before/after int are the same. It changes meaning when displaced relative to the '*' symbol – A. K. May 04 '12 at 03:54
  • I wrote another post about how const works, you can move the first const in front of the int with the same effect, though it gets a bit confusing when switching locations in mid-statement. – Greyson May 04 '12 at 03:54
  • 1
    @AdityaKumar Except that the 'consts' must go _after_ the pointer's stars; so I wrote it that way to be consistent. – Greyson May 04 '12 at 03:55
  • This should be useful for reading things: http://c-faq.com/decl/spiral.anderson.html. – chris May 04 '12 at 03:57
  • 1
    @BugalugsNash: I just finished typing my own answer. – Ben Voigt May 04 '12 at 04:00
  • @BenVoigt *facepalm* Yes, I see which reasoning you mean now. I'll edit. – Greyson May 04 '12 at 04:19