#include <iostream>
int main()
{
constint arr[] = { 7, 8, 9 }; // an array of three constants
intconst * num1 = arr; // a pointer to an array of constants
intconst * const num2 = arr; // a const pointer to an array of constants
++ num1; // Incrementing this poiner is allowed, because the pointer as such is not const.
std::cout << *num1 << std::endl;
// ++ num2; // Incrementing this pointer is not allowed, because the pointer as such is
// a constant.
intconst * const * const constPtr_of_constPtr_of_constInt = &num2; // This is valid, think about!
std::cout << **constPtr_of_constPtr_of_constInt << std::endl;
}
The rule is that const refers to the thing to it's left (the thing before it).
Obviously if it's the first word then there's nothing to it's left.
Only in that special case does it refer to the thing to it's right.
int main()
{
int x = 7;
x = 42;
intconst y = 6;
y = 42; // error: assignment of read-only variable 'y'
int * a = &x;
*a = 42;
a = nullptr;
int * b = &y; // error: invalid conversion from 'const int*' to 'int*'
intconst * c = &x;
*c = 42; // error: assignment of read-only location '* c'
c = nullptr;
intconst * d = &y;
*d = 42; // error: assignment of read-only location '* d'
d = nullptr;
int * const e = &x;
*e = 42;
e = nullptr; // error: assignment of read-only variable 'e'
int * const f = &y; // error: invalid conversion from 'const int*' to 'int*'
intconst * const g = &x;
*g = 42; // error: assignment of read-only location '*(const int*)g'
g = nullptr; // error: assignment of read-only variable 'g'
intconst * const h = &y;
*h = 42; // error: assignment of read-only location '*(const int*)h'
h = nullptr; // error: assignment of read-only variable 'h'
}
But you cannot exchange the order of between the *'s
but we can...! you wrote it on your code! it can be written as:
constint * p1;
dutch wrote:
The rule is that const refers to the thing to it's left (the thing before it).
Obviously if it's the first word then there's nothing to it's left.
Only in that special case does it refer to the thing to it's right.
Surely you have seen pointers to pointers? The most common examples are dynamically allocated 2D array, and passing a pointer to function that must modify the caller's pointer (in C, C++ should use reference). Most of those examples lack const correctness. https://isocpp.org/wiki/faq/const-correctness
nuderobmonkey said that you can't move the const in those declarations without changing the meaning.
Your "but we can...!" was about a different thing.
Modern C++ offers solutions that let us write most of the code without explicit plain pointers, let alone pointers to pointers.
Note the type of a2 and a3. These are const pointers to changeable memory. NOT a changeable pointer to const memory as might be expected. To get a pointer to const memory with auto, you have to specify auto*. See a5 and a6.
nuderobmonkey said that you can't move the const in those declarations without changing the meaning.
Your "but we can...!" was about a different thing.
no...! what he talking about is the position of the asterisk...!
but now maybe i got what he mean...
we can write either: [specifier] [type]
or
[type] [specifier]
and followed with asterisk(s)
coz, it's unable to declare it like this:
1 2 3
int * const p1;
//or
const* int p2;
edit:
but after i read your code, there's declarations like that, but maybe that's what he wanna say...
Lets rephrase: T ********sample;
(okay, that's really deep pointer to pointer to ...)
If we want that the concrete object fo type T is treated as constant, then we write: T const ********sample;
but, we may use the alternate syntax: const T ********sample;
However, if any of those asterisks has to be const-qualified, then the qualifier must be on the right side of that asterisk; there is no alternate syntax for that.
T *** * const ****sample;
Both the T and asterisks can be const-qualified. T const *** * const ****sample;
There is an alternate syntax; it could make the code easier to read:
1 2 3 4 5 6 7
using T = std::string ;
using const_T = const T ;
using ptr_to_const_T = const_T* ;
using ptr_to_T = T* ;
using const_ptr_to_T = const ptr_to_T ;
using const_ptr_to_const_T = const ptr_to_const_T ;
// etc.
Visualising a type alias for the pointer may also help remove the seeplus confusion about potential 'gotcha' with using auto with a pointer. It would make it easy to see that there is no gotcha; that the rules of template argument deduction are consistently used for auto type deduction.
const before * means value pointed by pointer is constant, value can't be changed. const after * mean the pointer is constant, pointer can't point to something else.
but you can type const multiple times for non pointer variables:
constconstconstconstint x = 0;
it's not an error but compiler will ignore redundant const keywords, and use just one.
You won't see this but some people see to write things like this:
constexprconstint x = 0;
but compiler will ignore const in this case.
for pointers thing like this:
constintconst * constint x = 0;
means second const before * is ignored, so the compiler takes it as:
there is probably a way to make an object that can use more consts if you really put some effort into doing so. I can't think of a practical use, but someone here will have an example.
the double const, think about what it means!
if only the pointer is constant, you can modify the data under it, but not point elsewhere.
if only the data is constant, you can move the pointer to another memory location, but not change the data.
if both are constant, its locked down both ways.