This question already has answers here:
Modifying a const int in C++ [duplicate]
(2 answers)
Closed 7 years ago.
I have this piece of code:
#include <iostream>
using namespace std;
class X {
public:
const int x;
X(int i) : x(i) { }
int getX() const { return x; }
};
int main()
{
const X d(45);
const_cast<X *>(&d)->x = 47;
cout << d.getX() << endl;
const int j = 3; // j is declared const
int* pj = const_cast<int*>(&j);
*pj = 4;
cout << *pj << endl; //should not work, like above
return 0;
}
As I found here, Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior. They even proceed to provide examples below, the second one I gave, stating that it should give undefined behavior.
However, on compiling the code and running (here), the second one gives no error, and prints out 4 consistently. Whereas the first one throws error:
assignment of read-only member 'X::x'
const_cast<X *>(&d)->x = 47;
Of course, removing the const from declaration of x in X makes it work fine. However, it is also of the same type of mischief as the first one, changing a const thing through pointer after casting it const_ptr<>. But the first one works while the second one doesn't. Why so?
Both demands undefined behavior which unfortunately could mean working sometimes.
int* pj = const_cast<int*>(&j);
*pj = 4;
Also, Not all compilers are smart enough to figure out this kind of indirect manipulation.
Const-casting anything other than an actual const ptr* is probably a terrible idea, even if it does actually work most of the time.
That being said, the reason why your code doesn't compile properly is pretty straightforward: you remove the constness of the X object, but you fail to also remove the constness of the x member you're trying to modify.
Try this:
*const_cast<int*>(&(const_cast<X*>(&d)->x)) = 47;
Related
In the following code
#include<iostream>
using namespace std;
int main(){
int x=4;
int y=5;
cout << x <<endl;
int& foo = x;
// foo is now a reference to x so this sets x to 56
foo = 56; //reseting the reference foo
cout << x <<endl;
cout << foo <<endl;
foo= y; //this is supposed to be forbidden
cout << foo <<endl; // but I am getting foo=5
return 1;
}
This is compiling fine and I get foo=5 in the last cout. For what I've read you cannot reseat a reference to make it refer to a different object, so I was expecting an error, what is going here?
Once a reference has been created, any attempt to use the reference variable is equivalent to using the object that was assigned to it.
So when we look at the following line of code:
foo= y; //this is suppose to be forbidden
We see that it does not attempt to re-assign the reference, it assigns the value of y to the object referred to by foo.
What would be an example of reseting a reference (that would generate an error), then?
While we can't write code that reassigns references, the compiler can end up in situations where it would have to emit code that is the equivalent of that when dealing with references embedded within other data structures. And it's still illegal for the compiler to do so.
For example, the following will fail to compile because the compiler-generated assignement operator for X cannot be created since it would involve reassigning ref.
struct X {
int& ref;
};
void foo() {
int v1 = 1;
int v2 = 2;
X x1{v1};
X x2{v2};
x1 = x2; // Boom!
}
Edit: Answering the followup question here because it's extremely relevant.
Now you may wonder: "Hey! if the reference behaves as a proxy for another variable, why can't the compiler just use that logic to generate a valid assignment operator for struct X?"
Well, not really. The underlying expectation here is that once i do var_a = var_b, then by default, var_a is now effectively the same as var_b.
So if x1.ref points to v1 and x2.ref points to v2, then the expectation is that by default, x1 = x2 would lead to x1.ref pointing to v2.
Doing anything else would just lead to confusion and surprises in the long run.
This question already has answers here:
Pointer vs. Reference
(12 answers)
Closed 6 years ago.
I found these two different sources, but they do the exact same thing. I was wondering if there is a difference or not but I couldn't figure it out.
Can anyone tell me the difference and when should I use which?
this is the first one:
void function1(int *x) {
*x = 100;
}
int main() {
int var1 = 10;
function1(&var1);
cout << var1 << endl;
}
and this is the second one:
void function2(int &x) {
x = 100;
}
int main() {
int var2 = 10;
function2(var2);
cout << var2 << endl;
}
int *x is a pointer whereas int &x is a reference. Probably the biggest difference is that you can't change where reference is pointing to.
The first is a pointer, the second is a reference. The ideas have some similarities, but there are also differences.
A pointer is a C and C++ mechanism and a bit more "pure" but gives you more posibilies for advanced concepts like pointer arithmetics. References are C++ only and are more safe and more implicit, as a reference is used with the same syntax as a normal varible while using the referenced one. A pointer is more explicit if you want to use or change its value, as you have to explicitely dereference it using *var, and explicitely have obtain it.
I was surprised that c++ allows incrementing dereferenced pointer to a constant data, which it should not allow through a pointer to a const data. Consider the code:
#include<iostream>
#include<climits>
using namespace std;
int main(){
int x = 2;
const int *xPtr2 = &x;
*xPtr2++;
cout << x << endl;
}
But still the value of x is 2. That means *xPtr2 was not actually incremented. I also tried *xPtr2 = 3, but this time it shows compilation error. Why is it so?
Here the precedence of ++ is more than that of *. Hence
*xPtr2++
is equivalent to
*(xPtr2++)
Since xPtr2 is not a constant pointer but a pointer to constant data, incrementing xPtr2 and dereferencing it is fine in this case (but not others) and hence no compilation error is caused.
The ++ operator has precedence over dereferencing. Basically you're dereferencing the pointer that has been incremented.
For the behavior you're trying to accomplish, you should wrap the pointer in parens.
(*xPtr2)++;
Same goes for assigning - you're trying to assign an int to a int *. It would work with parens.
(*xPtr2) = 3;
See your example in ideone.
You have mentioned
dereferencing pointer to constant data
So, lets consider the following code
#include <stdio.h>
int main() {
const int foo = 0xdead;
int* bar = (int*) &foo;
*bar = 0xcafe;
printf("const int foo = %#x", foo);
return 0;
}
Output : const int foo = 0xcafe
In C, C++ const is just a compile time modifier for variables. This means that the compiler wants no modification to a const at compile time. At runtime there is no concept of const => all local variables are stored in stack, all static and global variables are stored in .data section. Thus you can dereference a const and modify it only at runtime
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
The code snippet is as follows
#include <iostream>
using namespace std;
int a(int m)
{
return ++m;
}
int b(int &m)
{
return ++m;
}
int c(int &m)
{
return ++m;
}
int main(void)
{
int p=0,q=0,r=0;
p+=a(b(p));
q+=b(a(q));
r+=a(c(r));
cout<<p<<q<<r;
return 0;
}
The error occurring is invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int' at q+=b(a(q)). How to go about the error so that this program prints a desired output
Timothy J Williams is one or both of the following things:
wrong;
teaching C++ as it pertains to Visual Studio only, without disclaiming it, which is ill-advised.
References cannot bind to temporaries. It is not allowed in C++. Visual Studio allows it as a non-standard extension, but that's it. Some people get confused and think that means it's valid C++. It's not.
You will have to store the results of function calls like b(1) into named variables before you pass them anywhere by reference.
int main()
{
int p = 0, q = 0, r = 0;
int result_of_b_p = b(p);
p += a(result_of_b_p);
int result_of_a_q = a(q);
q += b(result_of_a_q);
int result_of_c_r = c(r);
r += a(result_of_c_r);
std::cout << p << q << r << '\n';
}
I should also note that the cited code is confusing and appears to serve no purpose other than for contrived "test your knowledge" challenges. I'd pay not too much attention to this and instead learn C++ from a proper book. After all, Timothy Williams claims that the above program outputs 322; it doesn't.
You cannot pass by reference a constant.
To break down your code.
int a(int m){
return ++m;
}
This will return an int (constant, eg. 5)
Then in
int b(int &m){
return ++m;
}
You are now technically passing in an integer (constant) not a variable into B. You must pass B in as a variable.
Try exactly what you have but passing in
int x = a(your_number_here);
int z = b(x);
EDIT:
int main(void){
int p=0,q=0;
int x = 5;
p = a(x);
q = b(p);
cout << q << endl;
return 0;
}
Returns 7.
The error is a result of trying to call a function that takes a reference with a value. It would be like calling b with a value literal b(1). That can't work...
The function call is where you pass by reference. See below:
void foo (int* m)
{
(*m)++;
}
int main (void)
{
int a = 0;
foo (&a);
cout << a << endl; // prints 1
}
So here b(int& m) takes a reference to an integer. Think about it this way. A reference is a "safe pointer" for which the compiler automatically handles the dereferencing operations.
The return value of a(int m) is a temporary, i.e. it is a temporary value that goes out of scope as soon as the function returns and its value has been utilized in some way. So you can do x = a(15); and x will become a copy of the returned 16. This is what an r-value is. A sort of "temporary" (r because it is on the right side of the expression). So when you have a pointer to a temporary value it does not make sense in most cases. For example in the following code
int* return_local() {
int a = 10;
return &a;
}
This will give you a compiler warning. Because you don't want to bind a pointer to a value which will go out of scope. Similarly you don't want a reference to an object that will go out of scope as soon as the function has returned and its value has been utilized. That is why there is an error in your code. a(int m) returns an r-value and when you do b(a(q) you are trying to bind a reference to an r-value
Now there is something called an r-value reference which takes the form void some_func(int&& rvalue_reference) in syntax. The && means r-value reference not reference to reference. Look it up if you are interested.
It's not allowed to pass a r-value as a non-const reference argument. This happens in the line whereyou call the function b with a(q) as its argument, which is an r-value (an expression which is not a simple variable).
So you need to first call a and store itsvalue in a variable, and then pass this variable to b:
int main(void)
{
int p=0,q=0,r=0;
p+=a(b(p));
int t=a(q);
q+=b(t);
r+=a(c(r));
cout<<p<<q<<r;
return 0;
}
This question already has answers here:
ampersand (&) at the end of variable etc
(5 answers)
Closed 3 years ago.
I am fairly new to programming. I am just moving on to C++ from C in my college courses, and I encountered something that I haven't seen before in C. Sometimes after the type, either in a function declaration or passing a parameter, a & immediately follows the type. For example, we use a struct called Customer in one of our projects, and some of the functions pass Customer&. Why is the ampersand after the type, as opposed to in front? Thanks!
References in C++ simply allow for a cleaner way to execute the following code:
int x = 16;
int* y = &x;
cout << *y;
Which could be written instead as
int x = 16;
int& y = x;
cout << y;
When defining functions, a reference allows a function to change the value of parameters without causing the user of the function to put an ampersand before everything. E.g.
void func( int& a )
{
a = 5;
}
void main()
{
int A = 10;
func( A );
cout << A; // Will output '5'
}
Be careful with this type of mutation, as a programmer using functions like this without checking the implementation might not realize that the function is changing the value of the parameters unless the intent is obvious. init_server(my_server) would be an example of a case where it's obvious, but to_json(my_struct) would clearly be an example where you should not be using a reference to change the struct in any way.
But, one of the most important uses of references, would be function like
int sum_vector( const vector<int>& a ) {
int sum = 0;
for( int i = 0; i < a.size(); i++ ) {
sum += a[i];
}
return sum;
}
If you tried to make sum_vector take in a vector, and you passed in a vector with 100 million entries, then it would have to copy them all over, taking forever. You could take in a pointer, but then the internal parts of the function would have to constantly dereference, and it must called with sum_vector(&myvec), which is more annoying than sum_vector(myvec). In this way, using a const reference, you can prevent the highly inefficient copying of the whole vector into the function body, while keeping syntax neat. Using const lets you reassure yourself that you're not going to change the vector that you were given. And, it also assures the user of your function that you won't change it. Similarly, void to_json(const some_struct&) would be a better function definition as it ensures you won't change the user's data.