C++ reference copying and assignment - c++

I have few questions regarding below code
#include <iostream>
using namespace std;
class A
{
public:
A & add(A & b);
};
A & A::add(A & z)
{
A * a = new A();
A & b = *a;
cout << "Inside add, address of a: " << &a << endl;
cout << "Inside add, address of b: " << &b << endl;
cout << "Inside add, address of z: " << &z << endl;
A aa;
cout << "Inside, add, address of aa: " << &aa << endl;
return aa;
}
int main()
{
A *a = new A();
cout << "Original a: " << a << endl;
A & b = a->add(*a);
cout << "b: " << &b << endl;
return 0;
}
Q1. Inside main, line 3, a->add(*a), the same object pointed by pointer *a is passed. But inside the function A::add(A &), when i try to achieve the same effect via A &b = *a, i get a different object. Why is this so?
Q2. Inside A::add(A &), i return a non const reference to a local object aa and main gets the same memory address as the local reference. So this has the effect of extending the lifetime of local reference, beyond its scope.
Q3. Inside A::add(A &), i dereference *a multiple times, first via A &b = *a and then by return *a. In both cases, the memory address is always the same. How is this happening? You can check the output of &b inside A::add(A &)and the result of A &b = a->add(*a)
UPDATE:
The issue related to Q1 was that i was doing cout << &a, when i should have been doing cout << a
To eliminate return value optimization, i compiled with -fno-elide-constructors. I am using g++.

A1: You created a new *a with A* a = new A() The a in main is different than the a in A::add. The a in main is referenced by the variable z
A2: No, you created a on the heap, so it is going to last until you call delete on that variable
A3: A dereference does not change the memory location that is stored in the pointer, it just gets the value stored in that location. A reference is more like an alias. So &b is like saying &(*a)

Related

Changing the address of a pointer to edit its value

recently we were trying to use pointer to void, by passing a copy of its address to an instance of a class, in order for the instance to allocate it to the same memory space as an OpenCV Mat it contains, and that is contained in a stack of memory shared by the GPU and CPU to compute it with OpenCV+CUDA.
However while doing that we ran into an issue we didn't quite understand. When passing the address of the pointer to the object, we tried to edit that address so that the pointer was hosted on another space. And while that worked once that copy ran out of scope the value of that pointer returned to being what it was (I'll add a code snip since its confusing to even explain it). However if we accessed the content of the pointer's address that we passed to the function, and edit that, the original pointer is edited.
My hypothesis is that when we passed the pointer's address to the function a copy of the value of that memory address is made, and if that pointer to pointer is edited, the content of it is left undisturbed, while on the other function we accessed the content and directly edited it, hence the copy is left undisturbed and runs out of scope, while the content is edited correctly.
Here is a snip of the code where I try both things:
// Example program
#include <iostream>
#include <string>
void change_value(int **p, int *addr)
{
*p = addr;
}
void change_direction(int **p, int *addr)
{
std::cout << "p value: " << p << std::endl;
std::cout << "p contains: " << *p << std::endl;
std::cout << "p contains contains: " << **p << std::endl;
p = &addr;
std::cout << "p value: " << p << std::endl;
std::cout << "p contains: " << *p << std::endl;
std::cout << "p contains contains: " << **p << std::endl;
}
int main()
{
int a = 1, b = 2, c = 3;
int *ptr = &a;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
std::cout << std::endl;
change_value(&ptr, &b);
std::cout << "change_value" << std::endl;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
std::cout << std::endl;
change_direction(&ptr, &c);
std::cout << std::endl;
std::cout << "change_direction" << std::endl;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
}
This is the output we got. We can see that while ptr is edited on change_value function, since we access to the content of p and edit it, it is not changed on change_direction, since the moment we edit p's address it stops pointing to ptr.
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe0c
ptr contains: 1
change_value
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe10
ptr contains: 2
p value: 0x710a27e3fe18
p contains: 0x710a27e3fe10
p contains contains: 2
p value: 0x710a27e3fdd8
p contains: 0x710a27e3fe14
p contains contains: 3
change_direction
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe10
ptr contains: 2
If anyone could offer a better explanation of what happened I'd be most grateful.
Cheers.
Not sure if I understand the question, but if this:
void change_direction(int **p, int *addr)
{
// ...
p = &addr;
// ...
}
Is supposed to modify the parameter passed to the function, then it isnt correct.
Parameters are passed by value unless you pass them by reference. Passing references is recommended, but if you like you can use pointers. However, then you need to modify what the pointer points to, not the pointer. In the function above p is local to the function. Modifying the value of p has no effect outside the function.
You probably want:
void change_direction(int **p, int *addr)
{
// ...
*p = addr;
// ...
}
Or rather
void change_direction(int *&p, int *addr)
{
// ...
p = addr; // p is a reference, hence no dereference needed
// ...
}
Actually you should prefer int*& here, because a nullptr is not a valid paramter (and thats about the only reason you would use a pointer rather than a reference).
#463035818_is_not_a_number offered a good answer that works well.
But there might be value in fully understanding what your original code is doing.
Beggining from the start:
int a = 1, b = 2, c = 3;
int *ptr = &a;
This initializes three pieces of memory in stack memory containing the int values you gave (a,b,c) and one more piece of memory for your ptr variable that holds the address of a.
You then print out the address and the values of ptr, which obviously doesn't change any of the values.
Next is the call to change_value(int **p, int *addr) which executes.
*p = addr;
The parameter p in this case holds an address to an address to an int somewhere in memory, so *p is the address pointed to by p.
Setting that to addr changes the address p points to.
So in your specific code:
change_value(&ptr,&b);
Sets the value of ptr to be the address of b.
Then next is the change_direction(int **p, int* addr) call (which probably should be named change_address), which executes (ignoring the printing):
p = &addr;
This sets the parameter p to be the address of addr.
But since in C/C++ all functions are called by value (in C there arent even any references, in C++ you have to specify it as #463035818_is_not_a_number mentioned), this doesnt do anything to the original values, that the function has been called with.
So the call:
change_direction(&ptr,&c)
Does not actually change what is held in ptr. At the beginning of the call to the function, the address of ptr (so &ptr) gets copied into a piece of stack-memory, which is then used in the function and freed after the function exits.
I hope this clears things up, pointers can be hard to wrap your head around sometimes.
Cheers.

How to comprehend "std::relational operators (shared_ptr) compares directly the stored pointers"

As per the documentation(http://www.cplusplus.com/reference/memory/shared_ptr/operators/), which says:
[emphasis mine]
The comparison compares directly the stored pointers (i.e., the value
the objects dereference to, and not their owned pointer (i.e., the
managed objects that are deleted on destruction), which may not be the
same in alias shared_ptr objects (alias-constructed objects and their
copies).
I can understand the example code in the documentation aforedmentioned to some degree.But I could not comprehend the quotes above.
Could somebody make it clear by giving some simple examlples and explain when using this operator makes sense?
I have been confused for a long time. I would be very grateful to have some help with this question.
Here is the example code which i can understand to some degree:
// shared_ptr relational operators
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> a,b,c,d;
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
c = b;
std::cout << "comparisons:\n" << std::boolalpha;
std::cout << "a == b: " << (a==b) << '\n';
std::cout << "b == c: " << (b==c) << '\n';
std::cout << "c == d: " << (c==d) << '\n';
std::cout << "a != nullptr: " << (a!=nullptr) << '\n';
std::cout << "b != nullptr: " << (b!=nullptr) << '\n';
std::cout << "c != nullptr: " << (c!=nullptr) << '\n';
std::cout << "d != nullptr: " << (d!=nullptr) << '\n';
return 0;
}
Let's say, you have this struct:
struct Foo { int a, b; };
Then you can generate aliased shared pointers like this:
void f()
{
// create
shared_ptr<Foo> orig(new Foo{1, 2});
// aliased pointer 1, points into object held by orig
shared_ptr<int> pa(orig, &orig->a);
// aliased pointer 2, ditto
shared_ptr<int> pb(orig, &orig->b);
assert(pa != pb); // passes
}
Even though pa and pb share ownership of the same object (which they happen to share with orig as well), they carry different pointers, just like you would expect.
I post an answer which has been deleted by its creator. I think it's helpful to comprehend the example code in the question. Hope it helps to the one who see this question.
A shared_ptr points to an object that it manages. It is the one you get by shared_ptr::get. Expression a == b on shared_ptrs a and b tests whether a and b point to the same object, i.e. whether a.get() == b.get(). It returns true in this case. If a and b point to different objects, even if these two objects compared equal, the result is false.
Let's have a look on the sample code:
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
This creates two shared pointers pointing to separate integer objects. Even if these two integer objects have the same value 10, they are still different objects. So a.get() will be different from b.get(), and, consequently a==b returns false.
However, once you assign
c = b
the two shared_ptrs b and c will point to the same object, such that b.get() returns a pointer to the same object as c.get(). Hence, c == b returns true.
That a and b point to different objects, whereas b and c share the same object, can be illustrated as follows:
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
c = b;
*b = 30; // change the value of the managed object.
std::cout << *a << std::endl; // still prints 10;
std::cout << *b << std::endl; // prints 30;
std::cout << *c << std::endl; // prints 30, as it points to the same integral object as b
Hope it got clearer.

New pointer in class method must be casted into a reference

I have two classes, let's call them A and B
class A:
{
public:
//Some functions
A *getNewA() const;
private:
//some attributes
}
class B:
{
public:
//Some functions
private:
A &reftoA;
}
In the main code, I must generate a new A thanks to the A::getNewA() method. And this must go to B::reftoA, as written in class B.
Here is the A::getNewA() method :
A *A::getNewA()
{
A *newA = new A;
return newA;
}
OK. So now I call getNewA and want to store the results in reftoA, which is a reference to A. In a B function (which take a reference to A as parameter)
B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
}
I thought this should have been working, but it won't.
Because when dereferencing, reftoA will always take the this object and not the new allocated object.
Let's be clearer and let's modify the functions to output the results
A * A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
}
void B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
std::cout << "new generated pointer " << &reftoA << std::endl;
}
Here is one of the output :
New pointer : 004FFAEC
this pointer: 0069D888
New generated pointer : 0069D888 //Expected : 004FFAEC
I can't get this "new generated pointer" to be the same than the new pointer the A::getNewA() returns after having allocated the memory. Of course, I guess there is some point with dereferencing the pointer to store it in a reference.
I know reference are used with existing object. Maybe the new object A::getNewA() should allocate memory for won't work as I expected.
I could use pointer instead reference in B::foo(), I know, but I can't
I think I am misunderstanding something about refrence and pointer, but I don't know what.
Any help greatly appreciated
The problem is that you can not reassign a reference. You can change only the value of the referenced object.
So you have to initialize the reference in the initializer list of the constructor of the class B.
Take into account that there is a typo in your code snippet
A*A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
^^^^^^^^^
}
I think you mean
A*A::getNewA() const
^^^^^
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
^^^^^^^^^^^
}
Always try to provide a verifiable complete example.
Here is a demonstrative program
#include <iostream>
class A
{
public :
//Some functions
A* getNewA() const
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
}
private :
//some attributes
};
class B
{
public :
B( const A& a ) : reftoA( *a.getNewA() )
{
std::cout << "&reftoA " << &reftoA << std::endl;
}
private :
A& reftoA;
};
int main()
{
A a;
B b( a );
return 0;
}
Its output is
New pointer 0x2b392afbec20
this pointer0x7ffd287ad0af
&reftoA 0x2b392afbec20
As you can see the values of the New pointer and &reftoA are equal each other.
To make it more clear consider a very simple example
#include <iostream>
int main()
{
int x = 10;
int y = 20;
int &r = x;
r = y;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "r = " << r << std::endl;
std::cout << std::endl;
std::cout << "&x = " << &x << std::endl;
std::cout << "&y = " << &y << std::endl;
std::cout << "&r = " << &r << std::endl;
return 0;
}
The program output is
x = 20
y = 20
r = 20
&x = 0x7ffd88ad47a8
&y = 0x7ffd88ad47ac
&r = 0x7ffd88ad47a8
This statement
r = y;
did not force the reference to refer the object y. It just reassigned the value of the referenced object x.
References have to be initialized when they are created.
Yes, you are misunderstanding something.
getNewA() is returning a pointer. it's not a smart pointer, you want to look into those and that's all I'll say on the matter.
on returning a pointer, you must keep a reference to this pointer else you will be unable to delete it and you'll get a memory leak. Thus you MUST have somewhere A* a = A::getNewA() and then later, when you no longer need it delete a;
Where you need to pass a reference to A, you can do foo(*a) which will dereference the pointer and pass a reference to the object it's pointing to.
But in summary, for all new code, smart pointers; there's no excuse to not use them.
Side note: Your code example had a few other issues; such as getNewA wasn't static; I'm going to take the code as a working example of your understanding, and not a working example.
Edit: On re-reading your example, the getNewA is intentionally non-static. I think this question is actually an XY problem (ie you're asking a question you've forced yourself into but isn't your actual problem); but I hope this addresses your misunderstanding of pointers and references.
You are not returning the pointer in the getNewA-Method
A* A::getNewA()
{
A *newA = new A;
return A; // you are returning A and not newA
}
And if you want to reassign the reference to a you can use a std::reference_wrapper
class B :
{
public :
void foo(A& paramA) {
reftoA = *(paramA.getNewA());
}
private :
std::reference_wrapper<A> reftoA;
}

Why can't a function change its argument object's address/reference value?

I learned that in Java and C, you can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
I thought I could see a different behavior in C++ due to its pass-by-reference feature, but my code seems to agree with the above statement...
void reassign(string & a);
int main()
{
string x = "abcd";
cout <<"x is " << x <<" at " << &x <<endl; //"x is abcd at 0x7bc7ebd5b720"
reassign(x);
cout <<"x is " << x <<" at " << &x <<endl; //"x is efgh at 0x7bc7ebd5b720"
}
void reassign(string & a)
{
a = string("efgh");
}
Since "string()" constructs a new string, why doesn't the "reassign" function change the original string's address?
Once an object is allocated, nothing can change its address. You can change its content (that is what your program does) but the address will stay the same for the lifetime of the object.
If you create an object dynamically with new, you would be able to assign a different object to the same pointer. However, the rule would stay the same: the address of the old object would not change, but you would be able to assign a new object to an old pointer.
void reassign(string* & a);
int main() {
string *x = new string("abcd");
cout <<"x is " << *x <<" at " << x <<endl; //"x is abcd at 0x95b7008"
reassign(x);
cout <<"x is " << *x <<" at " << x <<endl; //"x is efgh at 0x95b7030"
delete x;
return 0;
}
void reassign(string* & a) {
string *old = a;
a = new string("efgh");
delete old;
}
Demo.
You are confused because your analogy is not right. In Java, there is no such thing as an "argument object", because "objects" themselves are not values in Java (there are no "object types" in Java). The only types in Java are primitive types and reference types, where "references" are pointers to objects. So in Java you can only have pointers to objects as the value of a variable or parameter, and you only deal with objects through pointers to objects.
"you cannot change where that pointer points" is a consequence of pass-by-value. Java is always pass-by-value, which means assignment to the parameter cannot change the value of a passed variable. Remember that variables can only be of primitive type or reference type. Here you are talking about reference type. So the "value" of a variable of reference type is the reference (pointer to object), i.e. the address of the object it points to. Hence, you cannot change the value means you cannot change where the pointer points.
For example, in Java you might have something like this:
public static void reassign(String a) {
a = new String("efgh");
}
public static void main(String[] args) {
String x = "abcd";
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
reassign(x);
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
}
Here, x in main is a pointer to an object. a in reassign is also a pointer to an object. Assigning to the pointer parameter a in reassign has no effect on the passed pointer variable x (i.e. it does not affect where the pointer points to) because it's pass-by-value.
The equivalent of the above code in C++ would be like this:
void reassign(string *a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
return 0;
}
In addition to the pass-by-value shown above, C++ also has pass-by-reference, where assignment to a parameter has the same effect as assigning to the passed variable in the calling scope. Here is the exact same thing as above but with pass-by-reference:
void reassign(string *&a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x8673008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is efgh at 0x8673030
return 0;
}
Note that in none of the cases here did we change the object pointed to. We simply created a new object and tried to change the pointer to point to this object. The old object is still unchanged. The ability to change an object is an independent and orthogonal issue from pass-by-value and pass-by-reference, so we do not go into it here.

How to pointer-cast Foo** to const Foo** in C++

I have
class Fred
{
public:
void inspect() const {};
void modify(){};
};
int main()
{
const Fred x = Fred();
Fred* p1;
const Fred** q1 = reinterpret_cast<const Fred**>(&p1);
*q1 = &x;
p1->inspect();
p1->modify();
}
How would it be possible to do the
const Fred** q1 = &p1
via pointer-casting?
(I have just been reading that this might be possible)
Thank you for your answers. The const_cast works indeed for objects
#include <iostream>
#include <stdio.h>
using namespace std;
class Fred
{
int a;
public:
Fred(){};
Fred(int a_input)
{
a = a_input;
};
void inspect() const
{
cout << "Inspect called"<< endl;
cout << "Value is ";
cout << a << endl;
};
void modify()
{
cout << "Modify called" << endl;
a++;
};
};
int main()
{
const Fred x = Fred(7);
const Fred* q1 = &x;
Fred* p1 = const_cast<Fred*>(q1);
p1->inspect();
p1->modify();
p1->inspect();
x.inspect();
*p1 = Fred(10);
p1->inspect();
}
gives
Inspect called
Value is 7
Modify called
Inspect called
Value is 8
Inspect called
Value is 8
Inspect called
Value is 10
Inspect called
Value is 10
However, for predefined types it does not work:
int main()
{
const double a1 = 1.2;
const double* b1 = &a1;
cout << "a1 is " << (*b1) << endl;
cout << "b1 is " << b1 << endl;
double* c1 = const_cast<double*>(&a1);
cout << "b1 is " << b1 << endl;
cout << "c1 is " << c1 << endl;
double* d1 = static_cast<double*>(static_cast<void*>(c1));
cout << "d1 is " << d1 << endl;
cout<< "*d1 is " << *d1 << endl;
*d1=7.3;
cout<< "*d1 is " << *d1 << endl;
cout<< "*d1 address is "<< d1 << endl;
cout << "a1 is " << a1 << endl;
cout << "a1 address is" << &a1 << endl;
cout<< "*d1 is " << *d1 << endl;
cout<< "*d1 address is "<< d1 << endl;
double f1=a1;
printf("f1 is %f \n", f1);
}
is resulting in:
a1 is 1.2
b1 is 0xffbff208
b1 is 0xffbff208
c1 is 0xffbff208
d1 is 0xffbff208
*d1 is 1.2
*d1 is 7.3
*d1 address is 0xffbff208
a1 is 1.2
a1 address is0xffbff208
*d1 is 7.3
*d1 address is 0xffbff208
f1 is 1.200000
Apparently the g++ compiler optimizes such that it replaces a1 by 1.2 whenever it finds it, so, even if its value on the stack has changed, it does not care.
(In my case I had problems with directly reading the *b1, *c1, so I had to do the double static cast - the reinterpret cast did not work).
Is it any way to really change a1, compiling "normally", therefore not compiling without the optimization (so I overtake the optimization effect)?
This should do it:
Foo** f;
const Foo** cf = const_cast<const Foo**>(f);
This is not a good idea, because it violates type safety. Let me explain why:
Fred* pFred;
const Fred** ppFred = const_cast<const Fred**>(&p);
*ppFred = new const Fred; // Now pFred points to a const Fred
pFred->some_evil_mutating_method(); // can do, since type of *pFred is non-const!
You want const_cast.
Why don't you just make:?
const Fred** q1;
*q1 = p1;
Or you want to elide constness violation without const_cast? -- no, sir, you can't.
You should not do it. The fact that you cannot easily do the conversion is because it breaks constant correctness (and your code exercises it). Using the recommendations above your code will compile and will call a mutating method on a constant object (last line of code).
That is not recommended and in some rare cases could even kill your application (a constant global object could be stored in a read-only memory page), or leave it an unstable situation (you change the internal state of an object by changing through a constant reference into an internal member element, breaking the object invariants).
About your problem: C++ FAQ Lite [18.17]
you shouldn't need to do any casting for const Fred** q1 = &p1 as a non-const Fred** can be directly assigned to a const Fred** q1 in its declaration.