C++ slicing caused by reference - c++

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.

Related

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

How do I move multiple parameter via Move semantics?

Let us assume I have an Object MeasurementValues, which has n different pointers (this examples just show pointers to primitive types, but pointers to other complex objects mivght occur as well).
class MesaurementValues {
private:
int *measurement_1;
double *measurement_2;
long long *measurement_3;
//..
float *measurement_n;
int noPointer;
}
I know, this example might be a little bit contrived, anyway. I try to fullfill the Rule of Five in my code.
Do I have to
this.measurement_x = old.measurement_x ;// for all x = {1,..,n} ?
First off just be aware that move-semantics give no advantage over copy-semantics for plain-old-data type (POD) members, but it sure does when your class contains other class objects and/or arrays. When you implement move-semantics, it means you have a "move constructor" and/or a "move assignment operator" which would look like this in your class:
class MesaurementValues { private:
int *measurement_1;
double *measurement_2;
long long *measurement_3;
//..
float *measurement_n;
int noPointer;
//a couple different objects
someObject* pObj1;
differentObject* pObj2;
public:
MeasurementValues( MeasurementValues&& move ); //move-constructor
MeasurementValues& operator= (MeasurementValues&& move); //move-assignment
}
-Assuming your class has POD data and class objects, and
-assuming there are alot of variables to move over:
MeasurementValues::MeasurementValues( MeasurementValues&& old) {
//copy plain-old-data over
measurement_1 = old.measurement_1;
measurement_2 = old.measurement_2;
//copy over values of the pointers
pObj1 = old.pObj1;
pObj2 = old.pObj2;
}
Keep in mind that move-semantics, as other posters have said, only have an advantage if your data members are other moveable objects, or dynamically-allocated memory.
EDIT:
pointers in must become "invalid", as they've been moved. Therefore I would set them to null to prevent unexpected behavior:
MeasurementValues::MeasurementValues( MeasurementValues&& old)
: measurement_1() //null...
//,...
{
//Swapping null into old...
std::swap(measurement_1, old.measurement_1);
//...
}
Do I have to
this.measurement_x = old.measurement_x ;// for all x = {1,..,n} ?
I would rely on the pimpl idiom for this, and use something like a unique pointer. Below is a detailed example. Note you only have to work with Impl, and rely on its defaults (as it contains no pointers).
#include <iostream>
#include <memory>
struct Moveable
{
public:
Moveable();
~Moveable();
Moveable(const Moveable& m);
Moveable& operator=(const Moveable& m);
Moveable(Moveable&& m);
Moveable& operator=(Moveable&& m);
int foo() const;
private:
struct Impl;
std::unique_ptr<Impl> pimpl_;
};
//Moveable.cpp
struct Moveable::Impl
{
Impl(): a(1), b(2), c(3), buffer(){}
int a, b, c;
char buffer[10000]; //Make it worth our while...
};
int Moveable::foo() const{ return pimpl_->a+pimpl_->b+pimpl_->c;}
Moveable::Moveable()
: pimpl_(new Impl)
{
std::cout << "Default " << (void*)this << std::endl;
}
Moveable::~Moveable()
{
std::cout << "Destruct " << (void*)this << std::endl;
//automagically...
}
Moveable::Moveable(const Moveable&m)
: pimpl_(new Impl(*m.pimpl_))
{
std::cout << "Copying " << &m << " to " << (void*)this << std::endl;
}
Moveable& Moveable::operator=(const Moveable& m)
{
std::cout << "Copy assign " << (void*)&m << " to " << (void*)this << std::endl;
*pimpl_ = *m.pimpl_; //Relying on their defaults...
}
Moveable::Moveable(Moveable&& m)
: pimpl_(move(m.pimpl_))
{
std::cout << "Moving " << (void*)&m << " to " << (void*)this << std::endl;
}
Moveable& Moveable::operator=(Moveable&& m)
{
pimpl_ = move(m.pimpl_);
std::cout << "Move assigning " << &m << " to " << (void*)this << std::endl;
}
int main()
{
Moveable x;
Moveable y(x); //Copying...
y = x; //Copying assign
y = Moveable(); //Default construct, then move assignment, destruct temp
Moveable z(std::move(y));
std::cout << "Calling foo " << z.foo() << std::endl;
return 0;
}

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)

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.