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
Related
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 always thought std::initializer_list is a lightweight proxy object which would only take const references from list items, instead of copy them.
But then I discovered that copy is actually performed in this case:
struct Test {
Test() {
std::cout << this << " default ctor" << std::endl;
}
Test(const Test&) {
std::cout << this << " copy ctor" << std::endl;
}
~Test() {
std::cout << this << " destructor" << std::endl;
}
};
int main() {
Test a;
Test b;
Test c;
std::cout << "for begin" << std::endl;
for(const auto& current : {a, b, c}) {
std::cout << "Current: " << ¤t << std::endl;
}
std::cout << "for end" << std::endl;
}
Output of above code:
0x63e5acda default ctor
0x63e5acdb default ctor
0x63e5acdc default ctor
for begin
0x63e5acdd copy ctor
0x63e5acde copy ctor
0x63e5acdf copy ctor
Current: 0x63e5acdd
Current: 0x63e5acde
Current: 0x63e5acdf
0x63e5acdf destructor
0x63e5acde destructor
0x63e5acdd destructor
for end
0x63e5acdc destructor
0x63e5acdb destructor
0x63e5acda destructor
Why would std::initializer_list copy items in this case, instead of just taking their references? Is there any "elegant" way to write things similar to for(auto&& x : {a, b, c}), but without copying existing items?
From the documentation on std::initializer_list:
The underlying array is a temporary array of type const T[N], in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.
I wrote a simple program to learn more about the order of creating and destructing objects in C++ (using Visual Studio 2015). Here it is:
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
A(string name)
: name(name)
{
cout << "A(" << name << ")::constructor()" << endl;
}
~A()
{
cout << "A(" << name << ")::destructor()" << endl;
}
private:
string name;
};
class C
{
public:
C(string name, A a)
: name(name), a(a)
{
cout << "C(" << name << ")::constructor()" << endl;
}
~C()
{
cout << "C(" << name << ")::destructor()" << endl;
}
private:
string name;
A a;
};
class B
{
public:
B(string name)
: name(name)
{
cout << "B(" << name << ")::constructor()" << endl;
}
~B()
{
cout << "B(" << name << ")::destructor()" << endl;
}
private:
string name;
A a1{"a1"};
A a2{"a2"};
C c1{"c1", a1};
A a3{"a3"};
};
int main()
{
B b("b1");
return 0;
}
The output surprised me a little bit (the a1s):
A(a1)::constructor()
A(a2)::constructor()
C(c1)::constructor()
A(a1)::destructor()
A(a3)::constructor()
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor()
C(c1)::destructor()
A(a1)::destructor()
A(a2)::destructor()
A(a1)::destructor()
To learn more about what was going on I added information about the instances of objects:
A(string name)
: name(name)
{
cout << "A(" << name << ")::constructor(), this = " << this << endl;
}
~A()
{
cout << "A(" << name << ")::destructor(), this = " << this << endl;
}
The result was even more surprising:
A(a1)::constructor(), this = 0039FB28
A(a2)::constructor(), this = 0039FB44
C(c1)::constructor()
A(a1)::destructor(), this = 0039F8A8
A(a3)::constructor(), this = 0039FB98
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor(), this = 0039FB98
C(c1)::destructor()
A(a1)::destructor(), this = 0039FB7C
A(a2)::destructor(), this = 0039FB44
A(a1)::destructor(), this = 0039FB28
Namely, why is a1's constructor only called once and destructor 3 times? I'm passing a by value so obviously at least 1 temporary object is created but please explain to me when and how many A instances are created and destroyed?
As already noted in the comments, objects of type A are also constructed via copy-construction when you pass them as arguments by value. In order to see this you can add a copy-constructor on your own:
A(const A& other)
: name(other.name)
{
cout << "A(" << name << ")::copy-constructor(), this = " << this << endl;
}
Sample output:
A(a1)::constructor(), this = 0xbff3512c
A(a2)::constructor(), this = 0xbff35130
A(a1)::copy-constructor(), this = 0xbff350e8
A(a1)::copy-constructor(), this = 0xbff35138
C(c1)::constructor()
A(a1)::destructor(), this = 0xbff350e8
A(a3)::constructor(), this = 0xbff3513c
B(b1)::constructor()
B(b1)::destructor()
A(a3)::destructor(), this = 0xbff3513c
C(c1)::destructor()
A(a1)::destructor(), this = 0xbff35138
A(a2)::destructor(), this = 0xbff35130
A(a1)::destructor(), this = 0xbff3512c
Try it online
As you can see, one copy-construction happens when you pass a1 as parameter to the constructor of c1 and a second one happens when this constructor initializes its member a. The temporary copy is destructed immediately afterwards while the member is destructed when c is destructed.
Edit:
Here you can read the exact rules when a copy-constructor is created.
In order to not create a default copy-constructor it is not sufficient to provide any user-defined constructor, it needs to be a copy/move-constructor.
Edit2:
Taken from C++14 standard (12.8 Copying and moving class objects):
7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
This question already has answers here:
Why is the destructor of the class called twice?
(5 answers)
Closed 9 years ago.
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor" << endl; }
~A() { cout << "A's destructor" << endl; }
};
class B
{
public:
operator A() const { return A(); }
};
void f(A q) {}
int main()
{
B d1;
f(d1);
return 0;
}
Here's what I expected the code to do before I ran it:
The call to f results in a call to the converter function in class B which returns a temporary object. q's constructor gets called and when f exits, q's destructor gets called. I expected the following output:
A's constructor
A's destructor
but the output I got was:
A's constructor
A's destructor
A's destructor
Since there's another destructor, an extra object must have been created somewhere. Can someone explain what's happening here?
Use this as your class A:
class A
{
public:
A() { cout << "A's constructor: " << this << endl; }
A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a << endl; }
A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a << endl; }
~A() { cout << "A's destructor: "<< this << endl; }
};
And you'll see why.
The question has been asked many times before, but since it is so generic it is difficult to find the older posts.
You are passing your objects around by value, meaning that the copies are created by copy constructor. Copy constructor is what created that "extra object" in your case. Meanwhile, you do not output anything from the copy constructor and therefore don't see the calls.
You have to add a debug output to your copy-constructor as well. That way you will see what is actually constructed and when.
There's potential for there to be 3 A objects constructed here. First is the temporary object created by A() in the conversion operator. Then, since the return type of the conversion operator is A, that temporary is copied into the return value. Then the return value of the conversion is copied into the parameter q of f.
To copy an object, the copy constructor is invoked. The default constructor will not be invoked, so you won't see the "A's constructor" message being printed.
It just so happens that the compiler elides one of these copies so that you only actually have one copy occur. Which one is being elided, I can't tell you (but it's probably the copy into the return value).
I think first destructor call for temporary object and second destructor for object which is constructed by move semantic.
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.