I have 2 simple classes. Base class A, and a derived class B. For debugging purposes, copy constructor and destructor are overridden to cout stuff:
class A
{
protected:
char * c;
public:
A(char * c) : c(c) { cout << "+A " << this << "\n"; }
A(const A& other) : c(other.c) { cout << "*A " << this << "\n"; }
~A() { cout << "-A " << this << "\n"; }
};
class B : public A
{
public:
B(char * c) : A(c) { cout << "+B " << this << "\n"; }
B(const B& other) : A(other.c) { cout << "*B " << this << "\n"; }
~B() { cout << "-B " << this << "\n"; }
};
Here's how I insert an instance of B into the map:
{
cout << "-- 1\n";
map<string, A> m;
cout << "-- 2\n";
m.insert(pair<string, A>( "b", B("bVal")));
cout << "-- 3\n";
}
cout << "-- 4 --\n";
The result of that:
-- 1
-- 2
+A 0051F620
+B 0051F620
*A 0051F5EC
*A 00BD8BAC
-A 0051F5EC
-B 0051F620
-A 0051F620
-- 3
-A 00BD8BAC
-- 4 --
As regards creation of instances, I read this as follows:
B gets created by my own code
that B gets copy-constructed into an A by pair
that last A instance then gets copied once more by the map, where it is inserted
Btw changing the pair in the insert line to a pair<string, B> did not do the trick, it only changed the 2nd step to create an B instead of the A, but the last step would downgrade it to an A again. The only instance in the map that remains until the map itself is eligible for destruction seems to be that last A instance.
What am I doing wrong and how am I supposed to get a derived class into a map? Use maps of the format
map<string, A*>
perhaps?
Update - Solution As my solution is not stated directly in the accepted answer, but rather buried in its comments in form of suggestions, here's what I ended up doing:
map<string, shared_ptr<A>> m;
This assumes your build environment supports shared_ptrs - which mine (C++/CLI, Visual Studio 2010) does.
This is called slicing and happens when a derived class does not fit into the object it has been assigned to. This is the tirivial example:
B b;
A a = b; // This would only copy the A part of B.
If you want to store different types of object in a map, using map<..., A*> is the way to go, as you correctly deduced. Since the object is not stored inside the map but rather somewhere on the heap, there is no need to copy it and it always fits.
map<string, A> m;
will slice the inserted object, which will become an A, losing all other information (it is no longer a B).
Your intuition is correct, you'll need to use pointers or, better yet, smart pointers.
Also, the destructor in A needs to be virtual:
class A
{
//...
virtual ~A() { cout << "-A " << this << "\n"; }
};
otherwise deleting an object of actual type B through a pointer to an A leads to undefined behavior.
Related
I have a problem where I need to initialise a member object via a non-default constructor. However the compiler insists that I create a default constructor for the member object, which is called before the non-default constructor.
Consequently, the "this" pointer for the member object has different values in the default and non-default constructor but seems to stablise to the value in the default constructor.
I'm sure this is because I'm not using intialisation properly in C++, but I'm not sure what the correct way is to handle this.
Below is code which demonstrates the issue.
#include<iostream>
class my_object {
public:
my_object(int a) {
std::cout << "In non-default constructor for B\n";
std::cout << "Address of object is " << this << "\n\n";
}
my_object() {
std::cout << "In default constructor for B\n";
std::cout << "Address of object is " << this << "\n\n";
}
};
class my_first_object {
public:
my_first_object() {
std::cout << "In constructor for A\n";
std::cout << "The address of B is " << &B << "\n\n";
B = my_object(0);
std::cout << "We have just called the non-default constructor for B\n";
std::cout << "The address of B is " << &B << "\n\n";
}
my_object B;
};
int main() {
std::cout << "\n";
my_first_object A = my_first_object();
std::cout << "The address of A.B is " << &A.B << "\n";
return 0;
}
The output of this programme is
In default constructor for B
Address of object is 0x7ffee5d83ae8
In constructor for A
The address of B is 0x7ffee5d83ae8
In non-default constructor for B
Address of object is 0x7ffee5d83a90
We have just called the non-default constructor for B
The address of B is 0x7ffee5d83ae8
The address of A.B is 0x7ffee5d83ae8
You're loooking at this in two different objects - the second is created in the assignment
B = my_object(0);
which creates another my_object and assigns its value to B (which has already been created).
The only way to initialize members is to use the initializer list:
my_first_object() : B(0)
{
}
The reason for the compiler's insistence that you add a default constructor is that if you don't initialize a member in the initializer list, it is "default-initialized", and your code is equivalent to
my_first_object()
: B() // Initialization
{
B = my_first_object(0); // Assignment
}
Please see program here : http://cpp.sh/2oisg
You need to change, your my_first_object constructor like this:
my_first_object(int a = 0):B(a) {
std::cout << "In constructor for A\n";
std::cout << "The address of B is " << &B << "\n\n";
// B = my_object(0);
std::cout << "We have just called the non-default constructor for B\n";
std::cout << "The address of B is " << &B << "\n\n";
}
This way you are preventing a call to default constructor of my_object
I have a question regarding std::move function. Please refer to the code below:
#include <iostream>
#include <memory>
using namespace std;
class CPointer {
public:
CPointer(double a, double b)
{
m_dX = a;
m_dY = b;
}
~CPointer()
{
m_dX = m_dY = 0;
}
double getX() const
{return m_dX;}
double getY() const
{return m_dY;}
private:
double m_dX;
double m_dY;
};
class CContainer
{
public:
CContainer(CPointer* p)
{
m_p = p;
}
~CContainer()
{
m_p = nullptr;
}
CPointer* getP() const
{return m_p;}
private:
CPointer* m_p;
};
class CBigContainer
{
public:
CBigContainer(CContainer* p)
{
m_p = p;
}
~CBigContainer()
{
m_p = nullptr;
}
CContainer* getP() const
{return m_p;}
private:
CContainer* m_p;
};
int main()
{
CPointer* pPointer = new CPointer(150,360);
cout << "1.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";
std::shared_ptr<CContainer> spContainer = std::make_shared<CContainer>(pPointer);
cout << "2.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";
std::shared_ptr<CBigContainer> spBigContainer = std::make_shared<CBigContainer>(std::move(spContainer.get())); //<--- std::move here
cout << "3.) " << spBigContainer->getP()->getP()->getX() << " , " << spBigContainer->getP()->getP()->getY() << "\n";
cout << "4.) " << spContainer->getP()->getX() << " , " << spContainer->getP()->getY() << "\n";
cout << "5.) " << pPointer->getX() << " , " << pPointer->getY() << "\n";
return 0;
}
And this is the result :
My question is , I am using a std::move
std::shared_ptr<CBigContainer> spBigContainer = std::make_shared<CBigContainer>(std::move(spContainer.get()));
So I am expecting the spContainer cannot be used after the line of code, because the object inside smart pointer is removed.
But it still work fine. It seems like has no different with not using std::move in this case.
Can you explain to me in details ?
Thank you very much.
So I am expecting the spContainer cannot be used after the line of code, because the object inside smart pointer is removed.
Your code never actually requests any move operations. The smart pointers are a red herring, you could see the same behaviour in this case:
CContainer a(pPointer);
CBigContainer b( std::move(&a) );
The last line is the same as CBigContainer b( &a ); because the constructor of CBigContainer accepts a pointer, and the behaviour of move operations for primitive types (which includes pointers) is to leave the source unchanged.
Your code makes the CBigContainer object point to the CContainer object (the latter still being managed by a smart pointer). Which is a bad idea because if you then release the CContainer smart pointer, then the CBigContainer's pointer to it will dangle.
Your CContainer and CBigContainer objects hold raw pointers to other objects. Putting those objects in smart pointers doesn't change that.
In case you are unclear, these are two different things:
Move out of a smart pointer.
Move out of the object managed by a smart pointer.
The first one will leave the smart pointer empty. The second one leaves the smart pointer active and managing an object which is in a post-move state .
Here's an example of code that will move out of the spContainer:
std::shared_ptr<CContainer> other = std::move(spContainer);
This invokes a move operation because the shared_ptr on the left has a move-constructor
which accepts another shared_ptr of the same type as argument.
I have a compound class (instance containing other instance, nor pointer, nor reference).
When the container instance is destroyed, destructor of contained instance is called (I am ok with that, it's logic). But the issue is that if the contained instance is stack allocated destructor is called once again when reaching out of scope.
Is that a coding error or a compiler issue?
What is the cleanest way of fixing it?
Here is my sample:
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
int i;
A(int i_) : i(i_) {
cout << "A(): " << i << endl;
}
~A() {
cout << "~A(): " << i << endl;
}
};
class B {
public:
A a;
int b;
B(const A& a_) : a(a_) {
cout << "B(): " << a.i << endl;
}
~B() {
cout << "~B(): " << a.i << endl;
}
};
int main(void) {
for(int c = 0; c < 3; ++c) {
A a(c+1);
B b(a);
cout << b.a.i << endl;
}
return 0;
}
Output is:
A(): 1
B(): 1
1
~B(): 1
~A(): 1
~A(): 1
A(): 2
B(): 2
2
~B(): 2
~A(): 2
~A(): 2
A(): 3
B(): 3
3
~B(): 3
~A(): 3
~A(): 3
Compiler is gcc 7.3.0
The destructor is only called once per object. What you don't see in your output is that when you construct b, you create a copy of a using the copy constructor (which in your case is compiler-generated). That doesn't produce any output, but of course the destructor of the copy is also called.
If we add output to the copy constructor, we can see what actually happens:
A(const A& a_) : i(a_.i) {
cout << "A(const A&): " << i << endl;
}
The output shows that each A is copied once, leading to the "duplicated" (not really) destructor calls (live demo). If you want to avoid copying the object, look into C++11's std::move, which is explained in depth elsewhere on this site.
As indicated in the title above, my question is simply whether or not a C++ cast does create a new object of the target class. Of course, I have used Google, MSDN, IBM and stackoverflow's search tool before asking this but I can't find an appropriate answer to my question.
Lets consider the following implementation of the diamond problem solved by using virtual inheritance:
#include <iostream>
#include <cstdlib>
struct A
{
int a;
A(): a(2) { }
};
struct B: virtual public A
{
int b;
B(): b(7) { }
};
struct C: virtual public A
{
int c;
C(): c(1) { }
};
struct END: virtual public B, virtual public C
{
int end;
END(): end(8) { }
};
int main()
{
END *end = new END();
A *a = dynamic_cast<A*>(end);
B *b = dynamic_cast<B*>(end);
C *c = dynamic_cast<C*>(end);
std::cout << "Values of a:\na->a: " << a->a << "\n\n";
std::cout << "Values of b:\nb->a: " << b->a << "\nb->b: " << b->b << "\n\n";
std::cout << "Values of c:\nc->a: " << c->a << "\nc->c: " << c->c << "\n\n";
std::cout << "Handle of end: " << end << "\n";
std::cout << "Handle of a: " << a << "\n";
std::cout << "Handle of b: " << b << "\n";
std::cout << "Handle of c: " << c << "\n\n";
system("PAUSE");
return 0;
}
As I understood, the actual structure of B and C, which normally consists of both an embedded instance of A and variables of B resp. C, is destroyed since the virtual A of B and C is merged to one embedded object in END to avoid ambiguities. Since (as I always thought) dynamic_cast usually only increases the address stored by a pointer by the offset of the embedded (cast's) target class there will be a problem due to the fact that the target (B or C) class is divided into several parts.
But if I run the example with MSVC++ 2011 Express everything will happen as expected (i.e. it will run, all *.a output 2), the pointers only slightly differ. Therefor, I suspect that the casts nevertheless only move the addresses of the source pointers by the internal offset of B's / C's instance.
But how? How does the resulting instance of B / C know the position of the shared A object. Since there is only one A object inside the END object but normally an A object in B and C, either B or C must not have an instance of A, but, indeed, both seem to have an instance of it.
Or does virtual only delegate calls to A's members to a central A object without deleting the respective A objects of each base class which inherits virtual from A (i.e. does virtual actually not destroy the internal structure of inherited and therefor embedded objects but only not using their virtualized (= shared) members)?
Or does virtual create a new "offset map" (i.e. the map which tells the address offsets of all members relative to the pointer to a class instance, I dunno the actual term) for such casted objects to handle their "distributedness"?
I hope I have clarified everything, many thanks in advance
BlueBlobb
PS:
I'm sorry if there are some grammar mistakes, I'm only a beer loving Bavarian, not a native speaker :P
Edit:
If have added these lines to output the addresses of all int a's:
std::cout << "Handle of end.a: " << &end->a << "\n";
std::cout << "Handle of a.a: " << &a->a << "\n";
std::cout << "Handle of a.b: " << &b->a << "\n";
std::cout << "Handle of a.c: " << &c->a << "\n\n";
They are the same implying that there is indeed only one A object.
my question is simply whether or not a C++ cast does create a new object of the target class.
Yes, a cast to a class type would create new temporary object of that type.
Note that your example doesn't cast to a class anywhere: the only casts it performs are to pointer types. Those casts do create new instances of pointers - but not of the objects pointed to. I'm not sure what your example was supposed to demonstrate, nor how it is related to your stated question.
Also, dynamic_cast is unnecessary where you use it; an implicit conversion would work just as well.
Since (as I always thought) dynamic_cast usually only increases the address stored by a pointer by the offset of the embedded (cast's) target class
You must be thinking of static_cast or something. dynamic_cast is much more powerful. For example, it can cast from B* to C*, even though they are unrelated at compile time, by going down to END* and then back up the other branch. dynamic_cast utilizes run-time type information.
How does the resulting instance of B / C know the position of the shared A object.
This is implementation-dependent. A typical implementation would reserve space within the derived class instance to store an offset to its virtual base class instance. The constructor of the most-derived class initializes all those offsets.
No, you're just seeing the effects of multiple inheritance. In order for a pointer to be cast to a different base type, it has to be adjusted to the part of the object that represents that exact type. The compiler knows the original type of the pointer and the result type, so it can apply the necessary offsets. In order for the derived type to satisfy the "is-a" requirement it must have the necessary structure built in to emulate all of the base types.
There's one case where a cast can create a new object, and that's when you're casting to a type other than a pointer or reference type. Often that won't be possible unless you've defined a cast operator for that type.
The example you gave uses pointers.
A* a = dynamic_cast<A*>(end);
So the only "new" thing created here is another pointer, which will point to the "A" vtable of the object to which "end" points. It does not actually construct a new object of the class/struct types you are using.
Contrast with
A a;
B b(a);
Here a new object is created. But otherwise, casting does not create a new object of the destination cast type.
The reason the pointers differ is because they are pointing to the different vtables that preceed the data section of the underlying object.
Example:
#include <iostream>
using namespace std;
struct A {
int a[64];
A() { cout << "A()" << endl; }
A(const A&) { cout << "A(A&)" << endl; }
A& operator = (const A&) { cout << "A=A" << endl; return *this; }
};
struct B : virtual public A {
int b[64];
B() { cout << "B()" << endl; }
B(const B&) { cout << "B(B&)" << endl; }
B(const A&) { cout << "B(A&)" << endl; }
B& operator = (const B&) { cout << "B=B" << endl; return *this; }
B& operator = (const A&) { cout << "B=A" << endl; return *this; }
};
struct C : virtual public A {
int c[64];
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C&)" << endl; }
C(const B&) { cout << "C(B&)" << endl; }
C(const A&) { cout << "C(A&)" << endl; }
C& operator = (const C&) { cout << "C=C" << endl; return *this; }
C& operator = (const B&) { cout << "C=B" << endl; return *this; }
C& operator = (const A&) { cout << "C=A" << endl; return *this; }
};
struct END : virtual public B, C {
int end[64];
END() { cout << "END()" << endl; }
END(const END&) { cout << "END(END&)" << endl; }
END(const C&) { cout << "END(C&)" << endl; }
END(const B&) { cout << "END(B&)" << endl; }
END(const A&) { cout << "END(A&)" << endl; }
END& operator = (const END&) { cout << "END=END" << endl; return *this; }
END& operator = (const C&) { cout << "END=C" << endl; return *this; }
END& operator = (const B&) { cout << "END=B" << endl; return *this; }
END& operator = (const A&) { cout << "END=A" << endl; return *this; }
};
int main() {
END* end = new END();
A *a = dynamic_cast<A*>(end);
B *b = dynamic_cast<B*>(end);
C *c = dynamic_cast<C*>(end);
std::cout << "end = " << (void*)end << std::endl;
std::cout << "a = " << (void*)a << std::endl;
std::cout << "b = " << (void*)b << std::endl;
std::cout << "c = " << (void*)c << std::endl;
// the direct pointers are going to have to differ
// to point to the correct vtable. what about 'a' in all cases?
std::cout << "end->a = " << (void*)&(end->a) << std::endl;
std::cout << "a->a = " << (void*)&(a->a) << std::endl;
std::cout << "b->a = " << (void*)&(b->a) << std::endl;
std::cout << "c->a = " << (void*)&(c->a) << std::endl;
}
Which you can see running here: http://ideone.com/0QAoWE
At least with MSVC in VS 2017, the answer is a definite maybe.
// Value is a struct that contains a member: std::string _string;
// _value is a std::variant<> containing a Value as one member
template <> std::string const &Get<std::string>() const
{
// Required pre-condition: _value.index() == TYPE_VALUE
Value const &value = std::get<TYPE_VALUE>(_value);
return static_cast<std::string>(value._string);
}
std::string const &test()
{
static std::string x = "hello world";
return static_cast<std::string>(x);
}
Get() is a very small snippet from a much larger project, and won't operate without the support of several hundred other lines of code. test() is something I quickly threw together to investigate.
As written, Get()generates the following warning:
warning C4172: returning address of local variable or temporary
while test() compiles clean. If I remove the static_cast<> from Get(), it also compiles cleanly.
P.S. in hindsight, I ought to rename _value to something like _payload, since it can contain a lot more than a Value.
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.