From my understanding, const modifiers should be read from right to left. From that, I get that:
const char*
is a pointer whose char elements can't be modified, but the pointer itself can, and
char const*
is a constant pointer to mutable chars.
But I get the following errors for the following code:
const char* x = new char[20];
x = new char[30]; //this works, as expected
x[0] = 'a'; //gives an error as expected
char const* y = new char[20];
y = new char[20]; //this works, although the pointer should be const (right?)
y[0] = 'a'; //this doesn't although I expect it to work
So... which one is it? Is my understanding or my compiler(VS 2005) wrong?
Actually, according to the standard, const modifies the element directly to its left. The use of const at the beginning of a declaration is just a convenient mental shortcut. So the following two statements are equivalent:
char const * pointerToConstantContent1;
const char * pointerToConstantContent2;
In order to ensure the pointer itself is not modified, const should be placed after the asterisk:
char * const constantPointerToMutableContent;
To protect both the pointer and the content to which it points, use two consts.
char const * const constantPointerToConstantContent;
I've personally adopted always putting the const after the portion I intend not to modify such that I maintain consistency even when the pointer is the part I wish to keep constant.
It works because both are same. May be you confused in this,
const char* // both are same
char const*
and
char* const // unmutable pointer to "char"
and
const char* const // unmutable pointer to "const char"
[To remember this, here is a simple rule, '*' affects its whole LHS first]
That is because the rule is:
RULE: const binds left, unless there is nothing on the left, then it binds right :)
so, look at these as:
(const --->> char)*
(char <<--- const)*
both same! oh, and --->> and <<--- are NOT operators, they just show what the const binds to.
(from 2 simple variable initialization question)
A really good rule of thumb regarding const:
Read Declarations Right-to-Left.
(see Vandevoorde/Josutiss "C++ Templates: The Complete Guide")
E.g.:
int const x; // x is a constant int
const int x; // x is an int which is const
// easy. the rule becomes really useful in the following:
int const * const p; // p is const-pointer to const-int
int const &p; // p is a reference to const-int
int * const * p; // p is a pointer to const-pointer to int.
Ever since I follow this rule-of-thumb, I never misinterpreted such declarations again.
(: sisab retcarahc-rep a no ton ,sisab nekot-rep a no tfel-ot-thgir naem I hguohT :tidE
Here is how I always try to interpret:
char *p
|_____ start from the asterisk. The above declaration is read as: "content of `p` is a `char`".
char * const p
|_____ again start from the asterisk. "content of constant (since we have the `const`
modifier in the front) `p` is a `char`".
char const *p
|_____ again start from the asterisk. "content of `p` is a constant `char`".
Hope it helps!
In both of your cases you're pointing to a constant char.
const char * x //(1) a variable pointer to a constant char
char const * x //(2) a variable pointer to a constant char
char * const x //(3) a constant pointer to a variable char
char const * const x //(4) a constant pointer to a constant char
char const * const * x //(5) a variable pointer to a constant pointer to a constant char
char const * const * const x //(6) can you guess this one?
By default, const applies to what is inmediately at is left, but it could apply to what is inmediately at its right if there's nothing preceeding it, as in (1).
Related
I have a pointer:
const float *m_posBufferPtr_float;
I assign to this variable with:
m_posBufferPtr_float = reinterpret_cast<const float *>(buffer()->data().constData());
At which constData() function returns const char * type:
inline const char *QByteArray::constData() const
{ return d->data(); }
Therefore my reinterpret_cast should convert const char * to const float *.
But to my surprise, exactly before reinterpret_cast my pointer is:
and exactly after reinterpret_cast debugger shows my pointer as:
I wonder why reinterpret_cast is converting const char * to float rather than const float *
If you take this snippet:
int main(int argc, char *argv[])
{
float* pointer = nullptr;
float value = 12.34;
pointer = &value;
qDebug() << *pointer;
}
and execute it step by step, you will see in your debugger:
Then
Notice that the type became float when the pointer has been initialized. It's due to the configuration of the debugger.
In Qt Creator, right-click on your pointer and uncheck Dereference pointers automatically:
I have the following situation:
A function creates an array of strings and then passes this to a bunch of other functions. These other functions should not modify neither pointers pointed to by the outer pointer nor the strings themselves, so I made them const.
Minimal example:
void function(const char * const *arr) {
/* Do something useful */
}
int main(void) {
char **x;
/* fill x and *x */
function(x);
}
When compiling with gcc or clang this gives me a warning, that x is converted to an incompatible pointer type.
While I understand why the pointer type is incompatible if I remove the second const in the parameter list of function (explained here: Why does passing char** as const char** generate a warning?), I do not understand why it is incompatible with the const.
Compiling with a c++-Compiler does not give me the warning (See comparison here: https://gcc.godbolt.org/z/YND5U7)
I do not understand why it is incompatible with the const.
Note: const1, const2 defined for clarity to distinguish the two.
In C, the const2 in const1 char * const2 *arr is the qualifier x optionally matches. const2 say that function(const1 char * const2 *arr) has a contract with the calling code, it will not change what arr points to. arr points to a const1 char *. arr can be const1 char ** or const1 char * const2 *.
In main(), incompatible because *x points to a char * and not a const1 char *. What it points to is different than what function() expects. const1 is not part of the function() no-write contract. Instead, const1 char * is a type and that differs from char *.
At this point, I see no reason why C could not have been specified differently to allowed a char * to be treated like a const1 char * in function() - it is simply a case that C does not allow it.
#define const1 const
#define const2 const
void function(const1 char * const2 *arr) {
// Do something useful
}
int main(void) {
char **x = 0;
function(x); // bad
// note: expected 'const char * const*' but argument is of type 'char **'
const char **x2 = 0;
function(x2); // OK
}
No comment on C++
I saw someone using this in one answer:
void methodA(const int*& var);
I couldn't understand what the argument means.
AFAIK:
const int var => const int value which can't be changed
const int* var => pointer to const int, ie *var can't be changed but var can be changed
const int& var => reference to const int, ie value of var can't be changed
What does const int*& var mean? Is const int& *var also possible?
Can you please give some example as well, like what can and can't be done with it?
UPDATE:
I am not sure if I am thinking the right way, but I began to think of a reference as an alias of the variable that was passed as argument, so:
const int * p;
methodA(p) => here we are passing p as const int * but we don't know if this is pass by value or what, until we see the definition of methodA, so if methodA is like this:
methodA(const int * & p2) ==> here p2 is another name to p, ie p and p2 are the same from now on
methodA(const int* p2) ==> here p2 is passed as value, ie p2 is just local to this method
Please correct me if I am thinking the wrong way. If yes, I might need to study some more about this. Can you please point to some nice references?
UPDATE 2:
If some beginner like me wants to know more about this thing, you can use the c++decl / cdecl program from here, which I just discovered to be very useful.
$ c++decl
Type `help' or `?' for help
c++decl> explain const int&* p
declare p as pointer to reference to const int
c++decl> explain const int*& p
declare p as reference to pointer to const int
But, as every one here pointed out, the first example isn't legal in C++.
It is a reference to a pointer to an int that is const.
There is another post somewhat related, actually, here. My answer gives a sorta of general algorithm to figuring these things out.
This: const int& *var has no meaning, because you cannot have a pointer to reference.
If the const's and pointers are getting in the way, remember you can typedef these things:
typedef int* IntPointer;
typedef const IntPointer ConstIntPointer;
void foo(ConstIntPointer&); // pass by reference
void bar(const ConstIntPointer&); // pass by const reference
void baz(ConstIntPointer); // pass by value
Might make it easier to read.
If you need more help on C++, read this. More specifically, references.
References as variables do not take space:
int i; // takes sizeof(int)
int*pi = &i; // takes sizeof(int*)
int& ri = i; // takes no space.
// any operations done to ri
// are simply done to i
References as parameters use pointers to achieve the end effect:
void foo(int& i)
{
i = 12;
}
void foo_transformed(int *i)
{
*i = 12;
}
int main()
{
int i;
foo(i); // same as:
foo_transformed(&i); // to the compiler (only sort of)
}
So it's actually passing the address of i on the stack, so takes sizeof(int*) space on the stack. But don't start thinking about references as pointers. They are not the same.
Some folks find it easier reading this from right to left. So
const int*&
is a reference to a pointer to an integer that is const.
As you know, references cannot be changed, only what they refer to can be changed. So the reference will refer to just one pointer to an integer that is const. Since the pointer is not const - the integer is const - you can change the pointer to point to a different integer.
Compare this to
int* const &
This is a reference to a constant pointer to an integer. Again the reference is immutable, and in this case it is a reference to a constant pointer. What you can change in this case is the integer value since there was no const either side of the int keyword.
Just to add confusion, const int and int const are the same. However int const * and int * const are very different. The first is a pointer to a constant integer, so the pointer is mutable. The second is a constant pointer to an integer, so the integer is mutable.
Hope this helps!
In your example, var is a refernce to a pointer to const char.
Since it's a reference, a change to the parameter inside methodA() will be reflected in the argument that is passed to methodA():
void methodA( const char*& var)
{
static const char newdata[] = {'a', 'b', 'c', '\0'};
printf( "var points to %s\n", var);
var = newdata;
}
int main()
{
const char * p = "123";
printf( "p points to: %s\n", p); // prints "p points to: 123"
methodA( p);
printf( "now p points to: %s\n", p); // prints "now p points to: abc"
}
It is a reference to a const pointer, i.e. a pointer where you cannot modify the data pointed to. As the reference is used as an argument to a method the method is able to modify the pointer to let it point to something else (still something that cannot be modified).
With regards to your update:
so if methodA is like this methodA(const int * & p2) ==> here p2 is another name to p, i.e. p and p2 are same from now on and if methodA(const int* p2) ==> here p2 is passed as value i.e p2 is just local to this method
Yes, you are correct.
Here's another example, a getter that returns the address of a private data item. The item happens to be an int for simplicity. A large array of items would be a more practical case (a zero-copy getter).
#include <iostream>
using namespace std;
class X {
public:
void getter(const int *&data) const
{
data = &val;
}
private:
int val = 5;
};
main()
{
X obj;
const int *data;
obj.getter(data);
cout << data << endl;
cout << *data << endl;
}
I am surprised that the following behavior of C++ (Visual Studio 2012 compiler).
char * * PointerToPointerToChar = NULL;
char * const * PointerToConstPointerToChar = NULL;
char const * * PointerToPointerToConstChar = NULL;
PointerToPointerToConstChar = PointerToPointerToChar; // Assignment 1: Gives compiler error as I would expect
PointerToConstPointerToChar = PointerToPointerToChar; // Assignment 2: NO COMPILER ERROR ???
PointerToPointerToChar = PointerToPointerToConstChar; // Assignment 3: Gives compiler error as I would expect
PointerToPointerToChar = PointerToConstPointerToChar; // Assignment 4: Gives compiler error as I would expect
I understand the const keyword in C++, specifically how it's placement affects what is considered const (the entity to the left).
It seems like the compiler tries to protect the user of the RHS variable from a const-stripping alias at either level of indirection (assignments 3 and 4). But the LHS is only protected from a const-stripping alias at one level of indirection (assignment 1) and not the other level of indirection (assignment 2). In other words, given that the following is prevented by the compiler
PointerToPointerToConstChar = PointerToPointerToChar; // Assignment 1: Gives compiler error as I would expect
PointerToPointerToChar[0][0] = 'A'; // The user of the LHS variable was effectively lied to about the constness of the *characters* - second level of indirection
then why isn't the following also prevented by the compiler
PointerToConstPointerToChar = PointerToPointerToChar; // Assignment 2: NO COMPILER ERROR ???
PointerToPointerToChar[0] = NULL; // The user of the LHS variable was effectively lied to about the constness of the *pointers* - first level of indirection
Is this correct C++, and if so what is the rationale? It seems inconsistent. Thanks!
The type const* doesn't mean the value won't change, it means you can't change it using that pointer.
Because if you could do that, you could assign to the *PointerToPointerToConstChar any const char* - while PointerToPointerToChar relies on it being normal char*. If that was allowed:
PointerToPointerToConstChar = PointerToPointerToChar; // assume PointerToPointerToChar is pointing to a valid memory block
const char str[] = "Hello world!";
*PointerToPointerToConstChar = str;
(*PointerToPointerToChar)[0] = 'X'; // Oops, we just modified a const array
You have a Pointer to something that is const. The pointer is not const, just what it points to. You assign to that pointer a pointer to something that is not const. That is fine. The pointer is not const and the const in this case just tells us, that the object pointed to will not be changed through this pointer. It doesn't have to be const anywhere else.
char* c = someCharPointerSomewhere;
PointerToConstPointerToChar = PointerToPointerToChar;
*PointerToConstPointerToChar = c // const violation
*PointerToPointerToChar = c // this is fine
// now *PointerToConstPointerToChar will be c as well.
Then why can you not assign to a pointer to a pointer to const? Well, the pointer to const is a different type than a pointer to non const. The implicit conversion we have above does not apply in this case. You could use this pointer to let the pointer it points to point to something, that actually is const. Then the original pointer would allow to modify the const value indirectly.
const char c = 'c';
PointerToPointerToConstChar = PointerToPointerToChar;
*PointerToPointerToConstChar = c;
**PointerToPointerToChar = 'a'; // const violation!
It is a bit confusing, when you just read the explanations, but take your time and think it through. It really is logically consistent that way.
Assigning a char** to a char* const* is analogous to assigning a char* to a const char*. It makes perfect sense.
char array[] = "foo";
char* ptr1 = array; // Can change array through ptr1
char const* ptr2 = ptr1; // Can't change array through ptr2
Use of char** and char* const* complicates what can and what can't be changed a bit more.
char** ptrptr1 = &ptr1;
// Can change where ptr1 points to through ptrptr1
*ptrptr1 = <some other char*>; // OK
// Can change the value of what ptr1 points to through ptrptr1.
(*ptrptr1)[0] = 'x'; // OK
char* const* ptrptr2 = ptr1;
// Can't change where ptr1 points to through ptrptr2
*ptrptr2 = <some other char*>; // Not OK
// Can change the value of what ptr1 points to through ptrptr2.
// (*ptrptr2) is still of type 'char*'.
(*ptrptr2)[0] = 'x'; // OK
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?
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!
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.