int val2 = 38;
int *ptr = &val2;
const int *&ptrRef = ptr; // ERROR
int i = 92;
int &ref_i = i;
const int &ref_i2 = ref_i; // OK
Why I can't have a const reference that references to a non-const pointer? I thought that if you access the const ptrRef identifier, it will treat val2 as const. When you access ptr, it will treat val2 as non-const. This works for the bottom part of the code, so I don't understand why it won't work for pointers.
East-const makes it clearer:
int const * & ptrRef = ptr; // ERROR
It's the pointer that is const. However, ptr is a different type. You can't bind a reference to a different type. It requires a conversion, making the initializer a temporary (ptr converted to int const*).
Now, there's a more confusing catch: const references can bind to temporaries, extending their lifetime: Why do const references extend the lifetime of rvalues?
They e.g. allow funtions to take arguments by const& and still be callable with temporaries:
void foo(std::string const&);
foo("foor"s+"bar"s); // still ok
I think, your question boils to a simple typo. If you want a const reference to non-const pointer, use following:
int* const& ptrRef = ptr; // no error
This declares ptrRef as a const reference to non-const pointer. Another, perhaps cleaner option, is to introduce a typedef:
using intptr = int *;
const intptr& ptrRef = ptr;
Additionally, you can get out of business of manually specifying the type altogether:
const auto& ptrRef = ptr; // no error
And, for good measure, this would work (as in compile) too, if that is what you want:
const int* const& ptrRef = ptr; // no error
The latest bit declares constant reference to a constant pointer.
Related
This may sound like a silly question, but I was confused about this following behaviour:
void funcTakingRef(unsigned int& arg) { std::cout << arg; }
void funcTakingByValue(unsigned int arg) { std::cout << arg; }
int main()
{
int a = 7;
funcTakingByValue(a); // Works
funcTakingRef(a); // A reference of type "unsigned int &" (not const-qualified)
// cannot be initialized with a value of type "int"
}
After thinking about it this kind of makes sense because in passing by value a new variable is created and conversion can be done, but not so much when passing the actual address of a variable, as in C++ once variables are made their type can't really change. I thought it's similar to this case:
int a;
unsigned int* ptr = &a; // A value of type int* cannot be used to
// initialise an entity of type "unsigned int*"
But if I make ref function take a const the conversion works:
void funcTakingRef(const unsigned int& arg) { std::cout << arg; } // I can pass an int to this.
However not the same in the case of pointer:
const unsigned int* ptr = &a; // Doesn't work
I'm wondering what the reason for this is. I thought my reasoning was right that implicit conversion when passing by value made sense as a new variable is made, whereas because in C++ types never change once created you can't get an implicit conversion on a reference. But this doesn't seem to apply in a const reference parameter.
The point is the temporary.
References can't bind to variables with different type directly. For both cases int needs to be converted to unsigned int, which is a temporary (copied from int). The temporary unsigned int could be bound to lvalue-reference to const (i.e. const unsigned int&), (and its lifetime is extended to the lifetime of the reference,) but can't be bound to lvalue-reference to non-const (i.e. unsigned int&). e.g.
int a = 7;
const unsigned int& r1 = a; // fine; r1 binds to the temporary unsigned int created
// unsigned int& r2 = a; // not allowed, r2 can't bind to the temporary
// r2 = 10; // trying to modify the temporary which has nothing to do with a; doesn't make sense
const & allows the compiler to generate a temporary variable, which gets thrown away after the call (and the function can’t change it, as it is const).
For non-const, the function would be able to modify it, and the compiler would have to transfer it back to the type it came from, which would lead to all kinds of issues, so it’s not allowed/possible.
I'm currently trying to learn some C++ and came across following unintuitive behavior. As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int a = 3;
const int* t = &a; //Why is this allowed? a is NOT const int
a = 4;
cout << *t << endl; //This does then print 4
//*t = 4; //Throws error.
return 0;
}
Can anyone explain why this is does compile?
const int* t just means you can't change the value t pointing to by t, nothing more. The original value might be changed, but it has nothing to do with t's responsibility.
If you want to ensure the value won't be changed, you should let t point to a const, such as
const int a = 3;
const int* t = &a;
And for this case, you can't make a int* pointer point to it.
int* t = &a; // error
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
You cannot make that assumption in general, because t might point to a non-const object, such as in your example.
const int* t = &a; //Why is this allowed? a is NOT const int
Can anyone explain why this is does compile?
The rules of c++ allow the implicit conversion of T* to const T*. It is allowed, because it's very useful to have a pointer-to-const (or reference) to an non-const object. Pointer to const simply means that the object cannot be modified "through" the pointer. The object itself could be const, or non-const.
As an example of why it is useful, you could have some modifiable state as a private member of an object, and return const view to it so that others can observe, but not modify. A practical example of such is std::string::c_str(). It returns a const char* even though the internal buffer of the std::string is non-const.
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
The answer is simple: the const keyword in a pointer type declaration does not mean 'it is constant' but rather 'you are not allowed to modify it'.
This is useful for example when you create a variable and then call another function to do something with it, but you want to forbid modification:
extern int countZerosInArray( const int *array, int arrayLen);
int myVariableArray[ 100 ];
// ... fill the array - i.e. modify it!
int noOfZeros = countZerosInArray(myVariableArray, 100);
The countZerosInArray function is told it has read-only access to the array, although the array itself of course is not constant.
const int* t = &a; // int* or const int* can assgin to const int*
According to a book I'm reading:
we can use a pointer to const to point to a nonconst object:
I tried this:
int i = 42;
int *p1 = &i;
const int *const p3 = 0;
p1 = p3; //error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
Why is this? I tried this with ints and it worked. This is the from the book:
int i = 42;
const int ci = i;
int j = ci;
I thought pointers are objects as well?
A pointer to const is about privileges, not the fundamental type of the pointed-to object.
Essentially, with an int const * (which is the same as const int*), you can look at the int (which may or may not be const itself), but you can't change it. Casting a non-const pointer to a const one allows you to pass a pointer to your own data to a function and not worry that the function might modify it, even though you still can.
To preserve the above dynamic, you can't "get rid" of constness by assigning to another pointer.* That's what your error is saying. That is,
const int * constPtr;
int * nonconstPtr;
*nonconstPtr = 42; // legal
constPtr = nonconstPtr; // legal
*constPtr = 42; // illegal!
nonconstPtr = constPtr; // illegal!
* You actually can cast away constness with const_cast<>. And there are correct uses of the operation. But it is usually very wrong, and you should very probably avoid it.
int main()
{
const int* x;
int* pa = x;//removes const, so UB.
const int*& pb = pa;//error
int* pd = pb;//error
return 0;
}
I know that it's not possible to define a pointer to non-const data with a pointer to const data, because it would automatically cancel the constness out allowing me to modify the value.
But what is wrong with the second initialization? I know that a reference is an alias of something and how it works, but still don't get what actually is happening there at all. I guess that explanation of the second error will, hopefully, enlighten me the third error.
Can anyone shed some light? Thanks!
const int x = 1;
int* p;
const int*& r = p;
Imagine we had gotten this far. This last line will give the error you're questioning, but let's assume it works. Now r and p refer to the same pointer object. But now we can do this:
r = &x;
This makes r point at the const object x, which you might think is fine, but it will also make p point at it. Since p is an int* (not const), we can now use p to modify x:
*p = 2;
Now we've changed the value of a const object. The error in question prevents us from doing this.
So basically, the reasoning for this error is that being able to bind a reference to pointer to const to a pointer to non-const would give you a way to get the non-const pointer to point at a const object. That's bad.
See the Why am I getting an error converting a Foo** → Foo const** C++ FAQ to learn about the same issue but with pointers instead of references. The reasoning is the same.
This is just another instance of the rule that you cannot bind a temporary to a non-const refence.
E.g.
X f();
X& r = f(); // illegal
X const& cr = f(); // OK
You can convert a pointer to int to a pointer to const int but the result of that conversion is a new pointer with a different type. You cannot bind an rvalue (such as the result of this conversion) to a non-const reference, only to a const reference, e.g.
const int* const& pb = pa; // pb is not bound directly to pa but to
// the result of converting pa to const int*
I don't understand something here. In the following code I have defined an integer and a constant integer.
I can have a constant pointer (int* const) point to an integer. See the fourth line of code.
The same constant pointer (int* const) can not point to a constant integer. See the fifth line.
A constant pointer to a const (const int* const) can point to a constant integer. That's what I would expect.
However, the same (const int* const) pointer is allowed to point to a non constant integer. See the last line. Why or how is this possible?
int const constVar = 42;
int variable = 11;
int* const constPointer1 = &variable;
int* const constPointer2 = &constVar; // not allowed
const int* const constPointer3 = &constVar; // perfectly ok
const int* const constPointer4 = &variable; // also ok, but why?
int const constVar = 42; // this defines a top-level constant
int variable = 11;
int *const constPointer1 = &variable;
int *const constPointer2 = &constVar; // not allowed because you can change constant using it
const int *const constPointer3 = &constVar; // perfectly ok. here you can't change constVar by any mean. it is a low level constant.
const int *const constPointer4 = &variable; // also ok, because it says you can't change the value using this pointer . but you can change value like variable=15 .
*constPointer4=5; //you get error assignment of readonly location.because that pointer is constant and pointing to read only memory location.
You can always decide not to modify a non-const variable.
const int* const constPointer4 = &variable;
Just parse the definition: constPointer4 is a const (i.e you can't change what it is pointing to anymore) pointer to a const int (i.e. variable). This means that you can't modify variable through constPointer4, even though you can modify variable by other means.
THe other way around (accessing a const variable through a non-const pointer), you would need a const_cast.
Why is a pointer to const useful? It allows you to have const member functions in classes where you can guarantee to users that that member function does not modify the object.
const has less access rights than non const, thats why it is allowed. You will not be able to change "variable" through the pointer but that is not breaking any rules.
variable = 4; //ok
*constPointer4 = 4; //not ok because its const
You use this "const pointer to non const variable" situation a lot when calling functions.
void f(const int * const i)
{
i=4; //not ok
}
f(&variable);
A pointer to a const object cannot be used to modify that object. It doesn't matter whether someone else can modify it; it just can't be done through that pointer.
int i; // modifiable
const int *cip = &i; // promises not to modify i
int *ip = &i; // can be used to modify i
*cip = 3; // Error
*ip = 3; // OK
Line # 4
int* const constPointer2 = &constVar;
Here it should not be allowed because int* const part of the "int* const constPointer2" means that the pointer is contant and then when you go ahead and assign it to &constVar