The following code compiles fine. However I wonder if it is legal C++. So more specific, if I have a const object, am I allowed to modify variables through pointers/references of that object?
class Foo {
public:
int* a;
int& b;
Foo(int* _a, int& _b) : a(_a), b(_b) {}
};
int main ( int argc, char* argv[] ) {
int x = 7;
const Foo bar(&x, x);
*bar.a = 3; //Leagal?
bar.b = 7; //Legal?
return 0;
}
It's legal, as const-ness of the class means that the class member is constant. a is a pointer, so the address the pointer points to is constant, but the value stored at that address need not be.
Hence bar.a is effectively an int * const, not an int const *.
As, after initialization, a reference cannot be made to refer to another entity anyway, it does not matter for bar.b whether bar is declared const or not.
The constant variant of a pointer is a constant pointer, not a pointer to a constant. The constant variant of a reference is a reference, not a reference to a constant.
Small digression: You should be careful with references as members anyway in connection with const-ness, as the following will probably compile
struct Y { int m_a; };
struct X {
const Y & m_y;
X (const Y & y) : m_y (y) { }
};
Y y;
y.m_a = 1;
X x (y); // or const X x (y) -- does not matter
// X.m_y.m_a == 1
y.m_a = 2;
// now X.m_y.m_a == 2, although X.m_y is supposed to be const
As it is possible to assign a pointer to non-const to a pointer to const, you can build an analogous example with pointers. Remember that const does only guarantee that YOU will not modify a variable via this very variable, it cannot guarantee that the contents of the variable are not modified at all.
I find the best way to think about const in C++ is that it protects the physical bits of the object. It has no real protection for objects that it refers to. You can control the object definition with const methods to provide deeper protection of values but by default C++ really only protects the physical object itself
One of the reasons why C++ allows you to modify the contents of a pointer through a const value is that it really can't stop you. Imagine for a second that C++ disallowed that particular construct. You could trivially violate it by doing the following
size_t t1 = (size_t)bar.a; // legal
int* t2 = (int*)t1; // legal
*t2 = 3; // exactly the same as *bar.a = 3
Related
Here are the following code:
#include <iostream>
using namespace std;
class A {
public:
int *x;
};
int main() {
int b=100;
A a;
a.x = &b;
const A &m = a; // clause 1 - Is this top-level const?
int *r = m.x; // *r has no const yet allowed. Is it due to reference m being top level const?
}
Any help appreciated.
Thanks
int const ca = 24;
int a = ca;
You would expect this to compile right? And indeed it does. Here I initialized a integer with the value 24.
You code is the same situation, except that instead of integer you have pointer to integer:
m is const so m.x is const. The x is const, i.e. x cannot be modified (via m). In stricter terms m.x is of type int * const i.e. constant pointer to integer.
int *r = m.x
Here you just initialize the pointer r with the value of the pointer m.x. The fact that m.x is const is not an issue. Both types without their top level cv are identical: pointer to (mutable) integer.
const A &m = a; // clause 1 - Is this top-level const?
Yes Talking about top level const on references is strange indeed. A reference cannot be rebound. However if we are talking about the referenced type, i.e. const A then yes, it is top level. But then again talking about top level const is useful only on pointer types. E.g. int *const cp vs const int *p.
Consider the 2 snippets:
using x = int*;
int main () {
const x a = new int(3);
*a = 5;
}
and
int main () {
const int* a = new int(3);
*a = 5;
}
The first compiles, while the second doesn't
--> using is not equivalent to simply "plugging in" the type and then parse the line.
Are there more differences between using using and "inlining" the type directly?
The difference in interpretation is due to the way C++ declarations deal with pointer const-ness, which borrows its semantics from C. Basically, const int* x and int * const x mean different things, as explained in this Q&A.
In turn, this interpretation is due to the way the "anonymous" pointer types are derived syntactically: language designers decided to assigning const-ness to the pointed-to value, not the pointer itself, when const is at the front of the declaration.
Note that the same thing happens when you typedef a pointer type:
typedef int* x;
int main () {
const x a = new int(3);
*a = 5; // Works fine
return 0;
}
Essentially, adding a using or typedef makes C++ treat int* as a single type, with only one way of assigning const-ness. On the other hand, writing int* directly is treated as a "derived" pointer type, which is governed by a different set of rules.
This is related to the east-const (const on the right) / west-const (const is on the left) issue.
conston the left is only allowed only in one place: in the beginning of a type declaration. The rule is const is on the right to the type which it applies. And when it is written on the left, it is the same as been on the right of it's type.
So:
const int i1;
int const i2;
Is the same. (constant int)
And:
const int* i3;
int const* i4;
Is the same. (a pointer to constant int)
But with using we have a different situation.
const X i5;
X const i6;
Are the same.
So when we substitute for X the type we get:
int * const i6;
Which is a constant pointer to a (non-constant) int.
This is what you have to look out for.
For example, if F is a reference to an integer, where the reference is not permitted to be pointed to a new object once it is initially pointed to one.
Can I write to declaration like: const int & F?
I am confused about reference and pointer, because they both represent the address of something, but we always write parameter use reference as: const & F, I understand that this is to reduce the copy and does not allow others to change it, but are there any other meanings? and why do we need "const" after a function declaration like: int F(int z) const; this const makes the return type const or everything in the function const?
One more example,
void F(int* p)
{
p+=3;
}
int z=8;
F(&z);
std::cout<<z<<std::endl;
What is the output for z since z is a reference, and I pass it as a pointer who points to an integer.Increasing p by 3 just makes the address different and does not change its value?
Just a first pass at some answers - if anything is unclear please comment and I'll try to elaborate.
int a = 3;
declares an integer, a, with the initial value 3, but you are allowed to change it. For example, later you can do
a = 5; // (*)
and a will have the value 5. If you want to prevent this, you can instead write
const int a = 3;
which will make the assignment (*) illegal - the compiler will issue an error.
If you create a reference to an integer, you are basically creating an alias:
int& b = a;
, despite appearances, does not create a new integer b. Instead, it declares b as an alias for a. If a had the value 3 before, so will b, if you write b = 6 and print the value of a, you will get 6 as well. Just as for a, you can make the assignment b = 6 illegal by declaring it as const:
const int& b = a;
means that b is still an alias for a, but it will not be used to assign a different value to a. It will only be used to read the value of a. Note that a itself still may or may not be constant - if you declared it as non-const you can still write a = 6 and b will also be 6.
As for the question about the pointers: the snippet
void F(int* p) {
p += 3;
}
int z = 8;
F(&z);
does not do what you expected. You pass the address of z into the function F, so inside F, the pointer p will point to z. However, what you are doing then, is adding 3 to the value of p, i.e. to the address that p points to. So you will change to pointer to point at some (semi)random memory address. Luckily, it's just a copy, and it will be discarded. What you probably wanted to do, is increment the value of the integer that p points to, which would be *p += 3. You could have prevented this mistake by making the argument a int* const, meaning: the value of p (i.e. address pointed to) cannot be changed, but the value it points to (i.e. the value of z, in this case) can. This would have made *p += 3 legal but not the "erroneous" (unintended) p += 3. Other versions would be const int* p which would make p += 3 legal but not *p += 3, and const int* const` which would have allowed neither.
Actually, the way you have written F is dangerous: suppose that you expand the function and later you write (correctly) *p += 3. You think that you are updating the value of z whose address you passed in, while actually you are updating the value of a more-or-less random memory address. In fact, when I tried compiling the following:
// WARNING WARNING WARNING
// DANGEROUS CODE - This will probably produce a segfault - don't run it!
void F(int* p) {
p += 3; // I thought I wrote *p += 3
// ... Lots of other code in between, I forgot I accidentally changed p
*p += 3; // NOOOOOOOOOOO!
}
int main()
{
int z=8;
F(&z);
std::cout << z;
return 0;
}
I got a segmentation fault, because I'm writing at an address where I haven't allocated a variable (for all I know I could have just screwed up my boot sector).
Finally, about const after a function declaration: it makes the this pointer a const pointer - basically the compiler emits const A* this instead of just A* this. Conceptually, it states your intention that the function will not change the state of the class, which usually means it won't change any of the (internal) variables. For example, it would make the following code illegal:
class A {
int a;
void f() const {
a = 3; // f is const, so it cannot change a!
}
};
A a;
a.f();
Of course, if the function returns something, this value can have its own type, for example
void f();
int f();
int& f();
const int f();
const int& f();
are functions that return nothing, a (copy of) an integer, a (reference to) an integer, a constant (copy of) an integer, and a constant reference of an integer. If in addition f is guaranteed not to change any class fields, you can also add const after the brackets:
void f() const;
int f() const;
int& f() const;
const int f() const;
const int& f() const;
The way I remember the difference between references and pointers is that a reference must exist and the reference cannot change.
A pointer can be changed, and usually needs to be checked against NULL or tested to verify it points to a valid object.
Also, an object passed by reference can be treated syntactically like it was declared in the function. Pointers must use deferencing syntax.
Hope that helps.
You are confusing things.
First of all int z=8; F(&z); here z IS NOT a reference.
So let me start with the basics:
when found in a type declaration the symbol & denotes a reference, but in any other context, the symbol & means address of.
Similar, in a type declaration * has the meaning of declaring a pointer, anywhere else it it the dereferencing operator, denoting you use the value at an address.
For instance:
int *p : p is a pointer of type int.
x = *p : x is assigned the value found at address p.
int &r = a : r is reference of type int, and r refers the variable a.
p = &a : p is assigned the address of variable a.
Another question you have: the const at the end of a function, like int f(int x) const. This can be used only on non-static class methods and specifies that the function does not modify the object. It has nothing to do with the return value.
int main(){
int x = 10;
const int&z = x;
int &y = z; // why is this ill formed?
}
Why is initializing non constant reference to int to a constant reference not correct? What is the reason behind this?
Well, why shouldn't it be ill-formed?
It is ill-formed because it breaks the obvious rules of const correctenss. In C++ language you are not allowed to implicitly convert the constant access pass to a non-constant access path. It is the same for pointers and for references. That's the whole purpose of having constant access paths: to prevent modification of the object the path leads to. Once you made it constant, you are not allowed to go back to non-constant, unless you make a specific explicit and conscious effort to do that by using const_cast.
In this particular case you can easily remove the constness from the access path by using const_cast (this is what const_cast is for) and legally modify the referenced object, since the referenced object is not really constant
int main(){
int x = 10;
const int &z = x;
int &y = const_cast<int &>(z);
y = 42; // modifies x
}
Since y isn't const, you would be able to write y = 42 and change z (which is const) too.
Because a const reference is unmodifiable, while a standard reference is.
The compiler assumes that the thing referred to by a const int & is a const int, even though in this case it isn't. You cannot make a non-const reference refer to a const int, because you would then be able to change the (notionally) const int via the reference.
Because
int const x = 10;
int const& z = x;
int& y = z;
y = 42;
would modify a constant variable.
As others say, it would allow one to indirectly change x, which breaks the const-correctness promise. See http://en.wikipedia.org/wiki/Const_correctness
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is there a difference in C++ between copy initialization and direct initialization?
Is there any difference between,
int x(5);
int x = 5;
& What's the difference between,
int const x(5);
const int x(5);
Of the 4 lines you show, only 1 is valid C.
int x(5); /* INVALID C */
int x = 5;
int const x(5); /* INVALID C */
const int x(5); /* INVALID C */
I don't know the meaning of the invalid lines in other languages. In C, the meaning of the valid line is to create an object with name x, type int, and value 5.
To define a "const" (better: a "read-only") object, the C syntax is
const int x = 5;
int const x = 5;
but x cannot be used in places where only constants are allowed. x is not a constant: it is an object of type const int
#define CONSTANT 42
enum /*unnamed*/ { First=1, Second, Third };
switch (var) {
case x: break; /* invalid use of x; only constants allowed in case labels */
case 15: break; /* ok; 15 is a constant */
case CONSTANT: break; /* ok; CONSTANT is a constant with value 42 */
case Second: break; /* ok; Second is a constant with value 2 */
}
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
For the first, there's no difference for built-in types. For class types, the T x = y notation requires a copy constructor, the T x(y) notation doesn't. EDIT: Also, as one of the commenters pointed out, T x = y will not work if the T(y) constructor is declared explicit.
For the second, there's no difference as far as the compiler is concerned, but the second (const int) can lead to confusion in many cases, especially when typedefs are involved, e.g.:
typedef int* IntPtr;
IntPtr const cpi1; // Const pointer to a non-const int.
const IntPtr cpi2; // Also a const pointer to a non-const int.
In both definitions, the const applies to the pointer.
Because of this confusion, it's generally considered better practice to put the const after what it modifies. Now—for a long time, putting the const at the start was usual, with the result that the practice is widespread.
No both are exactly same until you are using an Argument. It's just a matter of coding style.
[Note: But Following are not same:
int x; // x is variable
int x(); // x is function declaration
]
About the const keyword:
It makes const what is immediately to its left
If there is nothing to the left, then it applies to the right.
So, int const i and const int i are the same.
But, int *const i and const int *i are not the same: in the first expression, the pointer is constant, in the second expression, the integer pointed to is constant. Als int const* i is equivalent to the second one.
No difference. Alternate ways to initialize the variable to a value.
But did you try this on your system? What did you get?
There's no difference in c++, in c, however - int x(5); is not allowed
int x(5);
int x = 5;
No difference.
int const x(5);
const int x(5);
No difference.
int x = 5;
const int *p = &x;
int *const q = &x;
Here is a difference in p and q. Using p you can't change the value of x, but you can assign a new address to p. Using q, you cannot point to any other memory location, but you can modify x using q.