Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does const auto and auto const apply to pointers?

Tags:

c++

c++11

I was try out some code and am wondering how the const qualifier in C++ applies to pointer types when using auto.

int main()
{
  int foo = 1;
  int bar = 2;

  //Expected: const int * ptr_to_const_int = &foo;
  const auto ptr_to_const_int = &foo;

  //Expected: int * const const_ptr_to_int = &foo;
  auto const const_ptr_to_int = &foo;


  *ptr_to_const_int = 3; //Thought this would error
  //ptr_to_const_int = &bar; This does error.
  *const_ptr_to_int = 3;

  return 0;
}

I realize there is a similar question asking if they are the same, I am asking more specifically what is the rule here that is getting applied to the deduction of the end pointer type.

like image 389
cogle Avatar asked Nov 09 '17 22:11

cogle


People also ask

What does const do to a pointer?

Constant Pointers A constant pointer in C cannot change the address of the variable to which it is pointing, i.e., the address will remain constant. Therefore, we can say that if a constant pointer is pointing to some variable, then it cannot point to any other variable.

Can const and auto be declared together?

It is perfectly legal for a compiler to deduce const for auto if it is not changing program functionality in any way. That also includes checks if there are const and non-const member functions available.

Does C++ auto deduce pointer?

C++ static code analysis: "auto" should not be used to deduce raw pointers.

Can pointer change const value?

A const pointer to a const value can not have its address changed, nor can the value it is pointing to be changed through the pointer. It can only be dereferenced to get the value it is pointing at.


1 Answers

In this example, const is being applied to whatever auto deduces, which means both uses result in an object of type int * const, because auto on its own is deducing int *. The ordering that you're imagining takes place based on whether you write it auto const or const auto doesn't happen, in the same way that int const and const int are the same.

An easier way to think about this might be to try the following:

template<typename T>
using pointer = T*;

pointer<int> ptr_to_int = new int;
const pointer<int> const_ptr_to_int = new int;
pointer<const int> ptr_to_const_int = new int;
const pointer<const int> const_ptr_to_const_int = new int;

pointer<int> const const_ptr_to_int2 = new int;
pointer<int const> ptr_to_const_int2 = new int;
pointer<const int> const const_ptr_to_const_int2 = new int;

pointer<int const> const const_ptr_to_const_int3 = new int;

Any variables in this example, whose names only differ due to appended numbers, are equivalent types, as far as C++ is concerned. Note how changing where the const appears doesn't affect the deduced type. This is because the "read-right-to-left" rule for working out how types are declared is based on how raw types are written: once you use constructions like this (or, as you observed, auto) the rules become a lot simpler.

My instinct is that, since your problem sort of implies that you need this kind of fine-grained control over the type system anyways, you should use a using or typedef on pointer<T> like I've showcased here, and use that to declare your types, since it's a lot easier to know, at a glance, what const pointer<int> is than it is to see what int *const is. Especially since it prevents silly mistakes like this:

int * a_ptr, b_ptr, c_ptr; //Oops! We meant b_ptr and c_ptr to also be pointers, but
//they ended up being regular ints!

pointer<int> a_ptr, b_ptr, c_ptr; //All of these are pointers, as we expected them to be

auto technically solves this problem too, but as you're showing in your example, it's still ambiguous (to you) whether the const is being applied to the pointer itself, or the object it's pointing to, whereas in this case, there's no more ambiguity.

like image 70
Xirema Avatar answered Sep 22 '22 19:09

Xirema