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.
Related
I discover this compiler trick and I cannot find a name for. Have you any idea?
On an Intel processor, I can cast a variable from its base class to an inherited class. It works with MSVC, gcc and clang and I am very confused.
#include <string>
#include <iostream>
class A
{
public:
virtual std::string print() const { return "A"; }
};
class B : public A
{
public:
std::string print() const override { return "B"; }
std::string printOther() const { return "other"; }
};
int main()
{
A a;
std::cout << a.print() << std::endl; // print A
std::cout << static_cast<const B&>(a).print() << std::endl; // print A
std::cout << static_cast<const B&>(a).B::print() << std::endl; // print B
std::cout << static_cast<const B&>(a).printOther() << std::endl; // print other
try
{
std::cout << dynamic_cast<const B&>(a).printOther() << std::endl; // throw std::bad_cast
}
catch (const std::bad_cast& e)
{
std::cout << e.what() << std::endl; // print std::bad_cast
}
std::cout << ((const B&)a).print() << std::endl; // print A
std::cout << ((const B&)a).B::print() << std::endl; // print B
std::cout << ((const B&)a).printOther() << std::endl; // print other
std::cout << reinterpret_cast<const B&>(a).print() << std::endl; // print A
std::cout << reinterpret_cast<const B&>(a).B::print() << std::endl; // print B
std::cout << reinterpret_cast<const B&>(a).printOther() << std::endl; // print other
// error: invalid 'const_cast' from type 'A*' to type 'const B*'
//std::cout << const_cast<const B&>(a).print() << std::endl; // print A
//std::cout << const_cast<const B&>(a).printOther() << std::endl; // print other
return 0;
}
Yes, static_cast can cast a class to a reference to a derived class. That is not a trick or compiler-specific. That is one of the specified purposes of static_cast in the C++ standard.
However, this cast has undefined behavior if the object isn't actually a base subobject of a derived class object.
In your case here you never created a B object, only a A object. Therefore all of the static_cast have undefined behavior and your program is broken.
(const B&)a effectively is defined to do the same as static_cast<const B&>(a) if the type B is a derived class type of the type of a. So all of them in your code also have undefined behavior and are broken.
dynamic_cast<const B&>(a) is allowed here since your class is polymorphic (has a virtual member function). It will work correctly and fail with an exception if a isn't actually a base subobject of a B object rather than causing undefined behavior.
dynamic_cast is the only cast that you may use if you are not sure that a actually is a base subobject of a B.
reinterpret_cast<const B&>(a) does something completely different than the above and also causes undefined behavior, because your classes are not standard layout and therefore definitively not pointer-interconvertible.
Let's say I have class A, with internal pointers. I declare variables:
A a;
A b;
A& c;
I would like "a = b" (or "b = a") to do a deep copy, but I would like "c = a" (or "c = b") to act as a reference and reflect changes made to a or b in the future.
I would have thought the the shallow copy/reference behavior for c was automatic, but I think I may have overloaded my assignment operator poorly because it gets called when I say "c = a"and still does a deep copy.
Existing assignment operator signature is: A& operator =( const A& a);
How do I have an overloaded assignment operator for deep copying, but maintain reference like behavior for references?
C++ wants a reference to act like just another name for the object to which the reference was bound. It specifically does not want users to be able to rebind references, to make a bound reference refer to a different object.
As such, if c is a reference to a, then every use of c will behave exactly as if you used a (with some minor exceptions, none of which are applicable for your uses). You cannot "maintain reference like behavior for references;" that's simply not what the language feature is for.
What you want is a pointer (or std::reference_wrapper, but pointers are generally what you want). That way, you can make the distinction between a rebind operation (c = &a) and a value assignment operation (*c = a).
This is not how references work in c++. A reference is bound to another variable only at the time of declaration. In fact, this code
A& c;
will not even compile. You must bind it to some other variable, like this:
A& c = a; // does not call operator= (no deep copy)
After this point however, assigning to c will call the copy assignment operator if you do c = b;, and this will do a deep copy. Note that since c is bound to a, this is the same as assigning b to a.
A& c;
That's not how we define a reference variable in C++. Reference should be
bound to an object at the point of their definition. After their creation, they can't be changed to point to something else.
The right way to do it:
A&c = a;
For the above point, there is no constructor being called. It's just that c is made an alias for the object a. However, if you do c = b, then copy assignment for objects a and b will be called as you can see below.
I would have thought the the shallow copy/reference behavior for c was automatic, but I think I may have overloaded my assignment operator poorly because it gets called when I say "c = a"and still does a deep copy.
c = a calls copy constructor of object a and b. Pointer in C++ would be better option for you. They can be changed to point to any object. See my example for pointers in main function below and it does the shallow copy (see no constructor or assignment operator being called).
An example to show what's being called for which object:
#include <iostream>
class A {
public:
A(void)
{
std::cout << "__CONSTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
A(const A& )
{
std::cout << "__COPY_CONSTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
const A& operator=(const A& other)
{
std::cout << "__COPY_ASSIGNMENT__" << std::endl;
std::cout << this << " and " << &other << std::endl;
return *this;
}
~A(void)
{
std::cout << "__DESTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
};
int main(void)
{
std::cout << "Example with reference" << std::endl;
std::cout << "------------ CREATING A ------------" << std::endl;
A a;
std::cout << "------------ CREATING B ------------" << std::endl;
A b;
std::cout << "------------ CREATING C ------------" << std::endl;
A& c = b;
std::cout << "-------------- C = A ---------------" << std::endl;
c = a;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Example with pointers" << std::endl;
std::cout << "------------ CREATING D ------------" << std::endl;
A *d;
std::cout << "-------------- D = &A --------------" << std::endl;
d = &a;
std::cout << "-------------- D = &B --------------" << std::endl;
d = &b;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Leaving the program" << std::endl;
}
Output:
Example with reference
------------ CREATING A ------------
__CONSTRUCTOR__
0x7fffe46d4ed6
------------ CREATING B ------------
__CONSTRUCTOR__
0x7fffe46d4ed7
------------ CREATING C ------------
-------------- C = A ---------------
__COPY_ASSIGNMENT__
0x7fffe46d4ed7 and 0x7fffe46d4ed6
Example with pointers
------------ CREATING D ------------
-------------- D = &A --------------
-------------- D = &B --------------
Leaving the program
__DESTRUCTOR__
0x7fffe46d4ed7
__DESTRUCTOR__
0x7fffe46d4ed6
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.
Why only one object of A is created in this program? and no copy constructor is called. What is this optimization called? If this is a valid/known optimization, will it not be a trouble for multiton design pattern?
#include <iostream>
#include <stdio.h>
using namespace std;
class A
{
public:
A () {
cout << "in-- Constructor A" << endl;
++as;
}
A (const A &a) {
cout << "in-- Copy-Constructor A" << endl;
++as;
}
~A() {
cout << "out --Constructor A" << endl;
--as;
}
A & operator=(const A &a) {
cout << "assignment" << endl;
++as;
//return *this;
}
static int as;
};
int A::as = 0;
A fxn() {
A a;
cout << "a: " << &a << endl;
return a;
}
int main() {
A b = fxn();
cout << "b: " << &b << endl;
cout << "did destructor of object a in func fxn called?" << endl;
return 0;
}
Output of above program
in-- Constructor A
a: 0x7fffeca3bed7
b: 0x7fffeca3bed7
did destructor of object a in func fxn called?
out --Constructor A
Go through link http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
It will help you.
This seems to be a case of a return value optimization. This optimization is notable in the C++ world as it is allowed to change the observable behavior of the program. It's one of the few, if not the only, optimization that's allowed to do that, and it's from the days where returning copies was considered a weakness. (With move semantics and generally faster machines, this is much, much less of an issue now.)
Basically, the compiler sees that it's going to copy the object, so instead it allocates room for it on the calling frame and then builds it there instead of calling the copy constructor.
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.