6

Possible Duplicate:
why isnt it legal to convert (pointer to pointer to non-const) to a (pointer to pointer to a const)

Hi I have the following code, but cannot wrap my head around why this doesn't work - I get an error saying "cannot convert from int** to const int**". However, if I change the first argument of printValues to be "const int *const * myArray", it all works fine. I know I probably shouldn't be using the one below anyway, but I don't understand why it doesn't compile at all. Can you not have a pointer to a pointer to a constant integer without declaring it constant in main()?

#include <iostream>

int printValues(const int ** myArray, const long nRows, const long nCols)
{
for (long iRow = 0; iRow < nRows; iRow++)
{
    for (long iCol = 0; iCol < nCols; iCol++)
    {
        std::cout << myArray[iRow][iCol] << " ";
    }
    std::cout << "\n";
}
return 0;

}

int main()
{   
const long nRows = 5;
const long nCols = 8;

int** myArray = new int* [nRows];

for (long iRow = 0; iRow < nRows; iRow++)
{
    myArray[iRow] = new int [nCols];
}

for (long iRow = 0; iRow < nRows; iRow++)
{
    for (long iCol = 0; iCol < nCols; iCol++)
    {
        myArray[iRow][iCol] = 1;
    }
}

printValues(myArray, nRows, nCols);

return 0;
}
Community
  • 1
  • 1
Dave Heath
  • 91
  • 2
  • 5
    See ["Why am I getting an error converting a Foo** → Foo const**?"](http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17) – James McNellis Jun 21 '11 at 16:43
  • Because it actually allows you to violate const-correctness. I'll try to find the dup. – Mark B Jun 21 '11 at 16:45
  • I never realized this was such a popular question, out of the all the answers I have seen I feel the [the one from standard](http://stackoverflow.com/a/29240053/1708801) is the best. – Shafik Yaghmour Mar 25 '15 at 11:52

3 Answers3

7
  • int ** is: "a pointer to a pointer to an integer".
  • const int ** is: "a pointer to a pointer to a constant integer".

A far-fetched analogy:

  • a note that describes the location of another note that describes the location of a jar
  • a note that describes the location of another note that describes the location of a closed jar

You can only put a cookie inside a jar that is not closed.

Now, think of replacing the second note with a photocopy of the first note. Do you have any guarantee that the ultimate jar that this note points to will be closed and cannot accept any cookies? The use of const is a contract and you cannot meet this contract by going through the indirection of two references.

Ates Goral
  • 137,716
  • 26
  • 137
  • 190
  • Its better to explain this by code, than by jar and cookie. jar and cookie are not C++ semantics, and so it would be very difficult to see the flaw if there is any in the analogy. – Nawaz Jun 21 '11 at 16:52
  • @Nawaz: Most people find it hard to wrap their minds around pointers, so I thought a tangible example would be helpful. I kinda left it to other answerers to present it in code terms... – Ates Goral Jun 21 '11 at 17:35
  • 3
    Cookies are certainly more delicious than pointers. – James McNellis Jun 21 '11 at 20:23
1

Edit:

You are violating const-correctness. By saying you want a pointer-to-a-pointer, you are setting yourself up by allowing the original const object to be modified. Const is a contract. By allowing this to happen without a cast, you are setting yourself up to allow a const object to be modified later on.

  • 1
    You can always convert non-`const` to `const`. Read @James McNellis' link for why this specific scenario converts `const` to non-`const`. – Billy ONeal Jun 21 '11 at 16:45
  • (in reference to 0A0D's comment) That's also true if I change the function argument to "const int *const * myArray" though, isn't it? And it compiles happily if I do that – Dave Heath Jun 21 '11 at 16:47
  • @0A0D: I don't know what you mean by that. You can do `void something(int* foo) { const int bar = *foo; }` all day long. – Billy ONeal Jun 21 '11 at 16:47
  • @Billy: The double-pointer is key. –  Jun 21 '11 at 16:49
  • @0A0D: I still don't see your point. Your answer says "passing a non-`const` integer that can be changed later and that is against the rules" -- huh? Obviously you can change a non-`const` integer. Your answer also says "you must define it initially as `const`", which is also false. You can create a constant pointer pointing to non constant data. – Billy ONeal Jun 21 '11 at 16:52
  • @0A0D: I still don't think this is a particularly *great* answer, but I have removed the downvote since your edit. – Billy ONeal Jun 21 '11 at 16:59
1

Basically, this is because it's possible via changing the level of indirection and other valid, non-const-violating semantics that you can work around the const if it's only on the top level. You have to add const on more than one level for the const to be actually safe.

Puppy
  • 144,682
  • 38
  • 256
  • 465