0

I work with multiple arrays at a time. There are functions which need to change the arrays, others only need to read. Take for instance these functions:

// Only needs to read from the two arrays.
void f(int const *a[2]) { /* ... */ }

// Changes the two arrays.
void g(int *a[2]) { /* ... */ }

I would expect that I could call them both with a non-const array. Adding a right-most const is always possible, a const on the left does change the type. Still I would think that a const there would only make it stricter and should be possible.

A data structure might look like this:

int *a[2] = {new int[10], new int[10]};

Calling g is not a problem, that compiles cleanly:

g(a);

However, when I try the same with f, it does not work:

f(a);

g++:

const_cast.cpp: In function 'int main(int, char**)':
const_cast.cpp:12:8: error: invalid conversion from 'int**' to 'const int**' [-fpermissive]
     f(a);
        ^

The message that clang++ gives is slightly different:

const_cast.cpp:12:5: error: no matching function for call to 'f'
    f(a);
    ^
const_cast.cpp:4:6: note: candidate function not viable: no known conversion from 'int *[2]' to 'const int **' for 1st
      argument
void f(int const *a[2]) {}
     ^

Then I have tried to use a const_cast to force this conversion:

f(const_cast<int const(*)[2]>(a));

That does not work, because it changes the number of indirections as well.

const_cast.cpp:22:36: error: invalid const_cast from type 'int**' to type 'const int (*)[2]'
     f(const_cast<int const(*)[2]>(a));
                                    ^

I do not want to relax the requirement on f, though. It should be clear to the user that this function will not alter the contents of the array. Also there are other cases in the codebase that I do not want to change.

Creating a new variable with the right const does work, however:

int const *const_a[2] = {a[0], a[1]};
f(const_a);

Is there a simpler way to do this?

1
  • 1
    Use std::array if the size is known at compile time, or std::vector if the size is dynamic. In addition to all other advantages you gain, you also get a simpler declaration syntax where adding const at the right place is trivial. Commented Mar 26, 2017 at 10:44

1 Answer 1

1

int const* and int* are unrelated types, and you can't convert a pointer to the latter into a pointer to the former.

You can't do this because it wouldn't be safe, but the problem isn't that the function might modify the array, it's that it could replace the array with one that isn't modifiable.

Consider

int const constants[] = {1,2,3};

void f(int const** a)
{
    *a = constants; // OK, *a and &constants[0] are int const*.
}

int main() 
{
    int* x;
    f(&x);
    x[0] = 0; // Modifying a const object; undefined behaviour.
}

(Note that in function parameters, T x[2] is equivalent to T x[]and T* x.)

Sign up to request clarification or add additional context in comments.

1 Comment

This also means that void f(int const *const a[2]) is a proper solution as well. This prohibits the thing that you have demonstrated and it seems to compile as well. This does changes the function arguments, though I realized that it is not a problem because the [2] has been added by myself as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.