So I have this code and I have a problem with passing the argument into the function. When I compile I get the following error: invalid initialization of reference of type 'const Point&' from expression of type 'const Point*'
struct Point
{
int x,y;
};
void printPoint(const Point& p)
{
cout<<"The X-coordinate is = "<<p.x<<"\nThe Y-coordinate = "<<p.y<<endl;
}
int main()
{
const Point p1 = {3,4};
printPoint(&p1);
}
&pi is of type Point* (it's the address of that object), use: printPoint(p1);
References are implicit. You do not need the &. In fact, that makes it a pointer (a const Point*, which is not implicitly convertible to a const Point&). Just do printPoint(p1);.
int main()
{
const Point p1 = {3,4};
printPoint(p1);
}
&p1 gives the address of p1.
this takes reference
void printPoint(const Point& p)
but you pass a pointer
printPoint(&p1);
so, use this one:
printPoint(p1);
Related
This question already has answers here:
Why is it allowed in C++ to modify a constant object's pointer member variable's memory from outside?
(4 answers)
Closed last year.
I declared this member function to take const reference to object.. So, I am expecting that when I try to edit anything in the object there will be an error.
But in the following code I tried to edit value in a member pointer and it works !!
m_ptr is a member pointer
void Test::takeObj(const Test& obj)
{
*obj.m_ptr = 3;
}
The const property is not transitive, when dereferencing pointers. You access the pointer m_ptras read-only, but this pointer itself is not a pointer to const. You write to the object pointed to by m_ptr, not m_ptr itself.
You could write two getter functions instead of a public access to the m_ptr member variable. One getter function is const and returns a pointer to const, one is not const and returns a normal pointer.
class Test {
private:
int* m_ptr;
public:
Test(int* ptr) : m_ptr(ptr) {};
const int* ptr() const { return m_ptr; }; // this overload is called for const Test object (const this*)
int* ptr() { return m_ptr; }; // this overload is called for non-const Test object
};
int main()
{
int a;
Test x(&a); // x is non-const
const Test& x2 = x; // x2 is const
int* p = x.ptr(); // okay
*p = 3; // okay
int* p2 = x2.ptr(); // error: invalid conversion from 'const int*' to 'int*'
*p2 = 4;
}
Then inside the const takeObj you can only access the const int* version of m_ptr.
Bonus info:
On C the test object (if it only contained an int*) would be a int**. The const parameter variant would had to be a const int* const*.
For learning purposes, I've written the following code:
void Swap(const int *&Pointer1, const int *&Pointer2)
{
const int *Tmp = Pointer2;
Pointer2 = Pointer1;
Pointer1 = Tmp;
}
I have a few doubts about this code and how top/low level constness works in such cases, with 3 or more "levels".
Obviously my references can't be const, otherwise I wouldn't be able to swap the pointers. Let's suppose however that the code would not touch the pointers values (the adresses they contain): the right syntax would be const int *(const &Pointer) or int * const &Pointer? I have the feeling the latter would mean "reference to a const pointer to const int, but I'm not sure. And if that is the case, the const part would be ignored by the compiler like a more simple const int pass by value or would not because it is under a reference?
Trying to call this function with pointer to int fails. However, it is possible to assign an int adress to pointer to const int and indeed I get no error if I simply remove the references. This makes me think that those references "forces" every const to perfectly match. Is this true? And if so, there is some way around it?
If you want Pointer to be const too, then it would be int const * const & Pointer, let's read it from right to left; so Pointer is a reference to const pointer to const int. (Note that means both Pointer itself and the int pointed by Pointer can't be changed either. This might conflict the intent of Swap.) And both the two const parts won't be ignored when pass-by-reference. Unlike pass-by-value, reference can't be top-level const qualified, and constness qualifed on what it refers to is reserved.
You can't pass int * to the function taking const int *& (i.e. lvalue-reference to non-const pointer). int * could convert to const int* implicitly, but the converted const int* is a temporary, which can't be bound to lvalue-reference to non-const. Temporary could be bound to lvalue-reference to const (or rvalue-reference), so change the parameter type to int const * const & Pointer as stated in #1, passing int * would be fine.
template <class P1,class P2>
void Swap(P1 && Pointer1, P2 && Pointer2)
{/*...*/}
int main()
{
const int a =1, b = 2;
Swap(&a, &b); // &a and &b - r-value, Pointer1 and Pointer2 param this 'const int* &&'
const int * const a_cref_p = &a;
const int * const b_cref_p = &b;
Swap(a_cref_p,b_cref_p); // a_cref_p and b_cref_p - l-value, Pointer1 and Pointer2 param this 'const int* const &'
const int * a_ref_p = &a;
const int * b_ref_p = &b;
Swap(a_ref_p,b_ref_p); // a_ref_p and b_ref_p - l-value, Pointer1 and Pointer2 param this 'const int* &'
return 0;
}
Are these definitions of pointer() equal?
class Example
{
public:
AnotherClass* const pointer() const;
AnotherClass* pointer() const;
private:
AnotherClass* m_pointer;
}
Does it guarantee me what somebody can't change m_pointer memory pointed to?
You need the return type for the first method to be one of these:
AnotherClass const * pointer() const;
or
const AnotherClass* pointer() const;
What you have done is return a const pointer to a non-const object.
What you want is a non-const pointer to a const object.
Also, to follow the typical practice your second method should not be const.
AnotherClass* pointer();
The two overloads for pointer only differ in the return type. Your C++ compiler will not accept that, this is an error.
Assuming that pointer() just returns m_pointer:
The declaration AnotherClass* pointer() const; would expose the value of m_pointer. Users of the class would not be able to change m_pointer, but they could change the object that m_pointer points to.
The declaration AnotherClass* const pointer() const; is quite similar to AnotherClass* pointer() const; but the value returned (the temporary pointer) is const. This declaration does not really make sense because you already can't change the return value in the first declaration. You can't write example.pointer() = nullptr in either cases. And when you assign the return value to a variable like in p = example.pointer() it makes no difference if the return value of pointer() is const or not.
The declarations const AnotherClass* pointer() const; and AnotherClass const * pointer() const; would expose the value of m_pointer. Users of the class would not be able to change m_pointer, and they would not be able to change the object that m_pointer points to.
There are a few things to consider here:
What is const: the pointer or the pointee?
Let's see the differences between these different declarations.
int x, y;
int * p = &x; // 0
const int * p = &x; // 1
int const * p = &x; // 2
int * const p = &x; // 3
const int * const p = &x; // 4
int const * const p = &x; // 5
(0) means that p can change (p = &y; is OK) and what it points to (x) can be changed via p (*p = y; is OK).
(1) and (2) are equivalent and mean that p can change (p = &y; is OK) and what it points to (x) cannot be changed via p (*p = y; is an error).
(3) means that p cannot change (p = &y; is an error) and what it points to (x) can be changed via p (*p = y; is OK)
(4) and (5) are equivalent and mean that p cannot change (p = &y; is an error) and what it points to (x) cannot be changed via p (*p = y; is an error).
An easy way to remember this is looking at the * and think that it separates the objects constness, that is,
(a) a const before * (e.g. const int * [...] or int const * [...]) means the pointed object (of type int) is const; and
(b) a const after * (e.g. [...] * const p [...];) means that the pointer is const and cannot be changed.
What happens if a function returns a const object?
Consider:
class some_class;
const some_class a(); // equivalent to 'some_class const a();'
someclass b();
const int c(); // equivalent to 'int const c();'
int d();
Then, (assuming some_class has an accessible assignment operator) we have:
some_class x;
a() = x; // illegal : the returned object is const
b() = x; // OK : the returned object is not const
It's natural to believe that c() and d() behave the same but this is not the case:
c() = 0; // illegal
d() = 0; // also illegal!!!
The reason is that if a function returns a fundamental type (e.g. int, bool, char, any pointer type, ...) then the returned object cannot be assigned to. Therefore,
returning a const object of fundamental type behaves the same as to returning a non-const one.
What about overloading on the return type?
Consider
int f(); // first overload.
double f(); // second overload.
This is illegal. We cannot overload on the return type only. One reason is that we can always ignore the object returned by a function. For instance, if overloading on the return type was allowed, then which overload of f would be called below?
int main() {
f(); // which f?
return 0;
}
Answering the question...
Consider the first declaration
AnotherClass* const pointer() const;
From what we have seen, this means that pointer() returns a const object of type AnotherClass* (a pointer type). Since a pointer type is a fundamental type, the function pointer above behaves the same as if it was declared as
AnotherClass* pointer() const;
which is the second overload. This is the first reason why having these two overloads doesn't make sense. But this is just a weak reason compared to the one that follows.
When I say "behaves the same" I don't mean "equivalent". The return type of the two overloads are different. As we have seen, we cannot overload on the return type only. This is illegal and the code doesn't compile.
Does it guarantee me what somebody can't change m_pointer memory pointed to?
No, again, both overloads behave the same and return a pointer to an object that can be changed via this pointer. What you want is this:
const AnotherClass* pointer() const { return m_pointer; }
// or
// AnotherClass const* pointer() const { return m_pointer; }
Notice the const at the left of *.
I want to implement a function who has to return a pointer to an array in C++, something like:
typedef double* ptr;
ptr func(size_t m) {
return A[m];
}
where A is a 2-D array defined globally (or as a member of the implementing class).
Now, I want to ensure that the returned array cannot be modified by the caller. I was wondering how can I declare the return type of the function to guarantee this.
I have tried to define it as:
const ptr func(size_t m) {
return A[m];
}
but I can write:
ptr x = func(5);
x[10] = 20.4;
and the above compiles without any problems.
Given the following code:
#include <stdlib.h>
static double A[100][100];
const double* func(size_t m) {
return A[m];
}
int main() {
double * x = func(5);
x[10] = 20.4;
}
GCC 4.8.1 reports:
foo.cc:10:21: error: invalid conversion from ‘const double*’ to ‘double*’ [-fpermissive]
double * x = func(5);
^
And Clang 3.3 reports:
foo.cc:10:11: error: cannot initialize a variable of type 'double *' with an rvalue of type 'const double *'
double * x = func(5);
^ ~~~~~~~
And to flesh out ComicSansMS's comment, because the comment he is responding to was deleted:
typedef double* ptr;
const ptr func(size_t m) {
return A[m];
}
This code is not the same as the code posted above. const ptr is a constant pointer to a double. The original code refers to a pointer to a constant double.
You could do something along these lines by doing:
typedef double* ptr;
typedef const double* cptr;
cptr func(size_t m) {
return A[m];
}
int main() {
ptr x = func(5);
x[10] = 20.4;
}
Which would report an error:
so.cc:27:6: error: cannot initialize a variable of type 'ptr' (aka 'double *') with an rvalue of type 'cptr' (aka 'const double *')
ptr x = func(5);
^ ~~~~~~~
const double* and double const* both indicate a pointer to a constant double. The user can modify where the pointer refers, but not the value pointed at.
double * const indicates a constant pointer to a double. The user can modify the value of the pointed to double, but not where the pointer refers.
double const * const indicates a constant pointer to a constant double. The user can not modify either the value of the double or where the pointer refers.
#include <iostream>
void f(const int * & p)
{
int i =0;
i = p[0];
std::cout << i << std::endl;
}
int main()
{
int * p =new int[1];
p[0] =102;
f(p);
return 1;
}
The gcc compiler gives error for this code:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: invalid initialization of reference of type ‘const int*&’ from expression of type ‘int*’
prog.cpp:5: error: in passing argument 1 of ‘void f(const int*&)’
But if I change the "f" function into
void f(const int * const & p)
Everything is ok. Can somebody explain why const behaves this way? thanks.
Going from int* to const int* requires creating a temporary const int* pointer and binding the reference const int*& to that temporary.
The Standard forbids doing that creating of a temporary for non-const references. You therefor need to make the reference const as you did your fix.
This is because non-const references mean "I want to change the argument that the caller passes using that reference parameter". But if the caller needs to convert their argument and ends up passing a temporary, the point of the reference is for naught, and so the Standard deems it an error to try and pass the temporary.
If the first conversion (int * to const int * &) were allowed, then you could write an evil function like this:
const int really_const[] = {1,2,3};
void evil(const int * & p)
{
p = really_const;
}
int main()
{
int not_const[3];
int * p = not_const;
evil(p);
p[0] = 0; // Whoops: modifying a const object
}
The second conversion is fine, since it prevents the function from modifying the pointer in this way.