Here is my situation:
I have a class that has a const reference member variable.
I attempt to initialize that member variable from a const reference.
My problem is that when the member variable is initialized in-class, a temporary copy of the object in question is made and the address of the temporary is used for the reference. When the member variable is initialized in the constructor initializer list, a copy is not made. Either way the program compiles fine without warnings in g++ 4.8.3 with either the c++11 or c++1y flags.
Below is a minimal program and output. I would just like to understand the rules of this better so I know why it occurs (or if it's a bug).
#include <iostream>
using namespace std;
struct A
{
A( )
{
cout << "creating an A at " << this << endl;
}
A( const A & a )
{
cout << "copying an A from instance at " << & a << " to instance at " << this << endl;
}
};
A g_aardvark;
const A & GetAardvark( )
{
cout << "returning an A at " << & g_aardvark << endl;
return g_aardvark;
}
struct B
{
B( )
: m_a1( GetAardvark( ) )
, m_a2( g_aardvark )
{ }
const A & m_a1;
const A & m_a2;
const A & m_a3{ GetAardvark( ) };
const A & m_a4{ g_aardvark };
};
int main( )
{
B butter;
cout << "B has m_a1 at " << & butter.m_a1 << endl;
cout << "B has m_a2 at " << & butter.m_a2 << endl;
cout << "B has m_a3 at " << & butter.m_a3 << endl;
cout << "B has m_a4 at " << & butter.m_a4 << endl;
return 0;
}
Sample output:
creating an A at 0x601494
returning an A at 0x601494
returning an A at 0x601494
copying an A from instance at 0x601494 to instance at 0x7fffc595f87f
copying an A from instance at 0x601494 to instance at 0x7fffc595f87e
B has m_a1 at 0x601494
B has m_a2 at 0x601494
B has m_a3 at 0x7fffc595f87f
B has m_a4 at 0x7fffc595f87e
This is a case of the infamous DR 1288. There was a defect in the published C++11 standard which inadvertently specified that the code:
const A & m_a4{ g_aardvark };
would actually create a temporary from g_aardvark and bind to that. This is nonsense of course, but g++ 4.8 followed the published text. The Standard was repaired by DR 1288 so that the reference binds directly.
Clang always implemented the sensible behaviour, but g++ did not update until the 4.9 chain.
See here for explanation with Standard references and a simpler testcase.
Appears to be a compiler bug as per Peregring-lk above
http://coliru.stacked-crooked.com/a/f30df5ef62b45420
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
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 am learning C++ primer 5th, and know that constructor initializers are required when a class defines reference member otherwise, compiler would complain about it.
However, I wrote a static factory method returing the class with empty statement.
#include <iostream>
using namespace std;
//Learning default initializing values.
class Default {
public:
Default(int t) : r(t) {}
static Default FromDefault() {}
friend ostream& operator<<(ostream& os, const Default& d) {
os << "c " << d.c << endl
<< "a " << d.a << endl
<< "b " << d.b << endl
<< "d " << d.d << endl
<< "l " << d.l << endl;
return os;
}
private:
int& r; //a reference which require to be initialized
char c;
int a;
float b;
double d;
long l;
};
int main() {
cout << Default::FromDefault();
return 0;
}
I thought the code won't pass the compiler but it did. As long as I do not use member r, no error would occur.
It seems that a reference class member failed to get initialized and I just wonder why compiler won't find out this error!
FromDefault exhibits undefined behavior, by way of reaching the closing brace without encountering a return statement.
On an unrelated note, Default(int t) constructor binds the reference r to the local variable. Once the constructor returns, t is destroyed and r becomes dangling. Any attempt to use it afterwards would exhibit undefined behavior.
So I have a perfect forwarder, and I want to appropriately capture it in a lambda, such that R-values are copied in, and L-values are captured by reference. However simply using std::forward doesn't do the job, as evidenced by this code:
#include<iostream>
class testClass
{
public:
testClass() = default;
testClass( const testClass & other ) { std::cout << "COPY C" << std::endl; }
testClass & operator=(const testClass & other ) { std::cout << "COPY A" << std::endl; }
};
template< class T>
void testFunc(T && t)
{ [test = std::forward<T>(t)](){}(); }
int main()
{
testClass x;
std::cout << "PLEASE NO COPY" << std::endl;
testFunc(x);
std::cout << "DONE" << std::endl;
std::cout << "COPY HERE" << std::endl;
testFunc(testClass());
std::cout << "DONE" << std::endl;
}
Compiling this with
g++ -std=c++14 main.cpp
Produces the output
PLEASE NO COPY
COPY C
DONE
COPY HERE
COPY C
DONE
In a perfect world, I would like to only have the "COPY C" appear in the rvalue case, not the lvalue case.
My work around would be to use a helper function overloaded for L- and R- values, but I was wondering if there was a better way.
Cheers!
You may use the following:
[test = std::conditional_t<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<std::remove_reference_t<T>>,
T>{std::forward<T>(t)}]
Live Demo
but providing helper function seems more readable
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.