New pointer in class method must be casted into a reference - c++

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;
}

Related

Questions about the ownership transfer of unique_ptr

For the following code:
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
struct pm
{
pm() : a(make_unique<vector<int>>(1, 10)){};
unique_ptr<vector<int>> a;
};
struct parms
{
parms() : a(make_unique<pm>()){};
unique_ptr<pm> a;
};
class test
{
public:
test() : p(make_unique<parms>()) {}
unique_ptr<const parms> getParms()
{
return move(p);
}
void setParms(int b)
{
p->a->a->push_back(b);
}
void pp()
{
cout << p->a->a->at(0) << "\n";
}
private:
unique_ptr<parms> p;
};
int main()
{
auto t = make_unique<test>();
t->pp();
cout << t->getParms()->a->a->at(0) << "\n";
cout << (t->getParms()==nullptr) << "\n"; ;
}
t->getParms() is a nullptr after we "cout << t->getParms()->a->a->at(0) << "\n";".
If we do the same thing for the ptr,
int main()
{
auto t = make_unique<test>();
t->setParms(5);
t->pp();
auto ptr = t->getParms();
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
}
ptr is not a nullptr.
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not? Is it because of the life scope of unique_ptr? Or the temporary rvalue? What's the reason behind this behavior?
Your method getParams() transfers ownership to the caller.
unique_ptr<const parms> getParms()
{
return move(p);
}
Member is moved to the return value and now the caller owns the pointee. You are not storing the returned value here:
cout << t->getParms()->a->a->at(0) << "\n";
Though, even if you did, t does not own the param anymore, hence when you ask t again:
cout << (t->getParms()==nullptr) << "\n"; ;
It doesnt know about the param anymore.
In the second example you transfer ownership from t to ptr:
auto ptr = t->getParms();
Now ptr owns the param. And you can inspect the pointer or the value as often as you like:
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
There is no transfer of ownership in those two lines.
What's the reason behind this behavior?
The reason, as stated above, is that getParams() transfers ownership to the caller. Thats rather uncommon for a getter method. Perhaps "stealer-method" would be a better name ;). If you don't want to give up ownership (and you are certain that the pointer is a valid one) you can simply return a reference:
const parms& getParms() const { return *p; }
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not?
t->getParms() transfers the ownership to the caller. This sets t->p to null. Since t->p no longer owns a pointer, there is nothing to transfer when you call t->getParms() a second time.
You never transferred ownership from ptr, so it hasn't been set to null.

Does this use of std::make_unique lead to non-unique pointers?

Suppose I have the following code in C++:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
As I understand, unique pointers are used to guarantee that resources are not shared. But in this case both p1 and p2 point to the same instance some.
Please unveil the situation.
They don't point to the same resource, they each point to a different copy of it. You can illustrate it by deleting the copy constructor to see the error:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
Some(Some const&) = delete;
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some); //error here
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
std::make_unique creates objects, calling constructor with specified arguments.
You passed Some& as parameter, and here copy constructor was invoked, and new object constructed.
So, p1 and p2 are 2 absolutely different pointers, but constructed from same object, using copy constructor
both p1 and p2 point to the same instance some
No, they don't.
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
p1->a = 42;
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
output:
5 5
42 5
To test whether two pointers point to the same object instance, you should compare the locations they point to, instead of the object member variables:
std::cout << &(*p1) << " " << &(*p2) << std::endl;
Which will show that they indeed do not point to the same instance.
ADDENDUM: As pointed out by Remy Lebeau, since C++11 it is advisable to use the
std::addressof function for this purpose, which obtains the actual address of an object even if the & operator is overloaded:
std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;

C++ reference copying and assignment

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)

C++ slicing caused by reference

I have problem to understand the behavior of the following code, which I modified from an example for C++ slicing:
#include <stdio.h>
#include <iostream>
struct B {
int x;
B() { x = 0; }
virtual void foo( const char* id ) {
std::cout << id << ": B=" << this << ", x=" << x << std::endl;
}
};
struct D1 : B {
int y;
D1() { x = 1; y = 100; }
virtual void foo( const char* id ) {
std::cout << id << ": D1=" << this << ", x=" << x << ", y=" << y << std::endl;
}
} d1;
struct D2 : B {
int z;
D2() { x = 2; z = 200; }
virtual void foo( const char* id ) {
std::cout << id << ": D2=" << this << ", x=" << x << ", z=" << z << std::endl;
}
} d2;
void main() {
std::cout << "d1 = " << &d1 << std::endl;
std::cout << "d2 = " << &d2 << std::endl;
std::cout << "By pointer at beginning: " << std::endl;
B* pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By Value: " << std::endl;
B b = d1;
b.foo( "d1" );
b = d2;
b.foo( "d2" );
std::cout << "By pointer after by value: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By reference: " << std::endl;
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
rb.foo( "rd2" );
std::cout << "By pointer after by reference: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
}
//The result is the following:
d1 = 0115B504
d2 = 0115B510
By pointer at beginning:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By Value:
d1: B=0036FE44, x=1
d2: B=0036FE44, x=2
By pointer after by value:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By reference:
rd1: D1=0115B504, x=1, y=100
rd2: D1=0115B504, x=2, y=100
By pointer after by reference:
pd1: D1=0115B504, x=2, y=100
pd2: D2=0115B510, x=2, z=200
From the above result, we can see that:
Value assignment causes slicing problem to the assign destination (b) by dropping the derived specific members, but leave the assign sources (d1 and d2) intact.
Reference assignment causes slicing to the assign destination (rd) by not assigning the derived specific members, thus partially changes the assign sources (d1 and d2).
At first, I was surprised that you can assign a reference to a different type (D2 to D1) via their base, until I realize the infamous C++ casting system. One conclusion seems that reference can only be initialized but not assigned.
We know that STL container for base object has slice problem because except list, all other STL container copy object around. It looks that STL container for base references should fair no better, unless it saves pointers inside.
How do you guys deal with this problem?
Thanks!
CP
I'm finding it hard to find a question in your text, but I'm going to assume it is something like:
"How do I polymorphically store objects in a standard container?"
First, let me just say that you can't store references in standard containers because you can't assign (rebind) them.
So the normal way is to have a container of base class pointers. If the container owns the items, then use smart pointers like unique_ptr or shared_ptr. If the container does not own the objects, then just use raw pointers.
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
The last line is equivalent as if you wrote
d1 = d2;
except it applies only to base class subobject. In the first line you set up the reference creating rb as alias to d1 with different static type. The reference can not be reseated. The later assign targets the object. d1 directly could only be assigned with using trickery with its op=, but your changed static type makes Base::op= work.
Many mentors say you should only use abstract classes as base, and most of the reasoning points to accidents like this.
In hierarchies you rarely have the op= left, if absolutely needed you have some virtual ssign thing that verifies compatibility.

Deriving a pointer type to the non-pointer class member

In book named "Using C++" by Rob McGregor there is following example of using pointer-to-member operator
class mycls
{
public:
int member;
int *ptr;
};
void main()
{
mycls MyClass;
// Derive a pointer type to the non-pointer class member
int mycls::*member = &mycls::member;
MyClass.ptr = new int;
mycls* pMyClass = &MyClass;
pMyClass->*member = 5;
*MyClass.ptr = 10;
cout << "pMyClass->*member = " << pMyClass->*member << "\n"; // pMyClass->*member = 5
cout << "MyClass.*member = " << MyClass.*member << "\n"; // MyClass.*member = 5
cout << "*MyClass.ptr = " << *MyClass.ptr << "\n"; // *MyClass.ptr = 10
cout << "*pMyClass->ptr = " << *pMyClass->ptr << "\n"; // *pMyClass->ptr = 10
delete MyClass.ptr;
}
In this example I don't understand why member variable mycls::member becomes maybe a pointer after (guessing) this line of code:
int mycls::*member = &mycls::member;
What this does?
Suppose you had a local variable:
int member;
You could make a pointer to it with:
int *ptr = &member;
To get the pointer to member syntax, we just append mycls:: in the appropriate places:
int mycls::*member = &mycls::member;
It might be clearer with an example that shows how the pointer can switch between any members of the class that are of the correct type:
class C
{
public:
int a;
int b;
};
void main()
{
// make pointer to member, initially pointing to a
int C::*ptrToMember = &C::a;
C x;
C *ptrToObj = &x; // make pointer to object x
ptrToObj->*ptrToMember = 2; // store in a;
ptrToMember = &C::b; // change pointer to b
ptrToObj->*ptrToMember = 3; // store in b;
}
Note how we create the pointer to the member a before we've created an object of type C. It's only a pointer to a member, not a pointer to the member of a specific object. In the 'store' steps, we have to say which object as well as which member.
Update
In the comments the OP asked if this is the same:
int *ptr = &(ptrToObj->a);
No, it's not. That is a pointer to any int, anywhere in memory.
The easiest way to understand this is to think of what it means technically. A "pointer" is an absolute location in memory: where to find an object. A "pointer-to-member" is a relative location, sometimes called an offset: where to find an object within the storage of an outer object. Internally they are just numbers. A pointer-to-member has to be added to an ordinary pointer to make another pointer.
So if you have a pointer to an object (an int is an object!), you can use it to change what is stored at that absolute location in memory:
*ptr = 123;
But if you have a pointer-to-member, it is not a memory location. It is an offset, an amount to be added to a memory location. You cannot use it by itself. You must "add" it to an object pointer:
ptrToObj->*ptrToMember = 132;
This means: go to the location in memory ptrToObj, then move along by the distance ptrToMember.
He called the class member member and the pointer-to-member member, confusing the issue. Does renaming them like this help?
Class:
class SampleClass
{
public:
int m_data;
int* m_pointer;
};
Usage:
int main()
{
SampleClass sample;
// Derive a pointer type to the non-pointer class member
int SampleClass::*pointerToMember = &SampleClass::m_data;
sample.m_pointer = new int;
SampleClass* pSample = &sample;
pSample->*pointerToMember = 5;
*sample.m_pointer = 10;
// pSample->*pointerToMember = 5
cout << "pSample->*pointerToMember = "
<< pSample->*pointerToMember << "\n";
// sample.*pointerToMember = 5
cout << "sample.*pointerToMember = "
<< sample.*pointerToMember << "\n";
// *sample.m_pointer = 10
cout << "*sample.m_pointer = "
<< *sample.m_pointer << "\n";
// *pSample->m_pointer = 10
cout << "*pSample->m_pointer = "
<< *pSample->m_pointer << "\n";
delete sample.m_pointer;
}
[Code]
Edit: Re "I'm still currious whether int *ptr = &(ptrToObj->a); is the same as using pointer to a member like in the book":
It's not a pointer-to-member. It is just a normal pointer to memory that happens to be in an object.
You can see the syntax in use here:
Class:
class C
{
public:
int a;
int b;
};
Usage:
int main()
{
// make pointer to member, initially pointing to a
int C::*ptrToMember = &C::a;
C x = {10, 11};
C *ptrToObj = &x; // make pointer to object x
cout << "a initial value: " << ptrToObj->*ptrToMember << endl;
ptrToObj->*ptrToMember = 2; // store in a;
cout << "a after change: " << ptrToObj->*ptrToMember << endl;
ptrToMember = &C::b; // change pointer to b
cout << "b initial value: " << ptrToObj->*ptrToMember << endl;
ptrToObj->*ptrToMember = 3; // store in b;
cout << "b after change: " << ptrToObj->*ptrToMember << endl;
int* ptr = &(ptrToObj->a);
cout << "ptr to a: " << *ptr << endl;
ptr = &(ptrToObj->b);
cout << "ptr to b: " << *ptr << endl;
}
[Code]
The asterisk character in the declaration is part of the type.
Your declaration breaks down into
Type: int mycls::*
Variable name: member
Initialiser: = &mycls::member
This new variable member points is a member pointer to an int held in a mycls. It doesn't have to point to a mycls::member.