Could you explain me the output of the following code? The variable changes it's value at the end of assignment.
#include <iostream>
#include <new>
using namespace std;
template<class CRTP>
class object_t {
public:
object_t<CRTP> &operator=(const object_t<CRTP> &a) {
((CRTP*)this)->~CRTP();
new ((CRTP*)this) CRTP(*(const CRTP*)&a);
cout << "Value in assignment: " << ((CRTP*)this)->n << endl;
return *this;
}
};
class darr_t : public object_t<darr_t> {
public:
int n;
darr_t(const darr_t &a) : n(a.n + 1) {
cout << "Value in constructor: " << n << endl;
}
darr_t(int pn) : n(pn) {}
};
int main() {
darr_t tmp(42);
darr_t tmp2(55);
tmp = tmp2;
cout << "Value in main: " << tmp.n << endl;
return 0;
}
Output:
Value in constructor: 56
Value in assignment: 56
Value in main: 55
Expected output:
Value in constructor: 56
Value in assignment: 56
Value in main: 56
Edit:
Thanks to #Cheersandhth.-Alf and #Mr_Hic-up answers!
The problem is that default darr_t::operator= first calls base type's assignment but after that it calls assignment(overrides) for members of darr_t object!
You are observing the behavior because:
The compiler defines an implicit copy assignment operator for darr_t.
The implicit copy assignment calls the copy assignment operator of the base class first before performing copy assignment of the member variables.
Here's relevant documentation from http://en.cppreference.com/w/cpp/language/as_operator:
Implicitly-declared copy assignment operator
If no user-defined copy assignment operators are provided for a class type (struct, class, or union), the compiler will always declare one as an inline public member of the class. This implicitly-declared copy assignment operator has the form T& T::operator=(const T&) if all of the following is true:
each direct base B of T has a copy assignment operator whose parameters are B or const B& or const volatile B&
each non-static data member M of T of class type or array of class type has a copy assignment operator whose parameters are M or const M& or const volatile M&
Otherwise the implicitly-declared copy assignment operator is declared as T& T::operator=(T&). (Note that due to these rules, the implicitly-declared copy assignment operator cannot bind to a volatile lvalue argument)
new ((CRTP*)this) CRTP(*(const CRTP*)&a);
That pointer magic you're trying to pull isn't doing what you expect it to. Adding some lines to print out the addresses of the object before printing the variable yields (on my machine):
Address in constructor: 0x7fff56264610
Value in constructor: 56
Address in assignment: 0x7fff56264610
Value in assignment: 56
Address in main: 0x7fff56264618
Value in main: 55
Related
I wrote the following program to test when the copy constructor is called and when the assignment operator is called:
#include
class Test
{
public:
Test() :
iItem (0)
{
std::cout << "This is the default ctor" << std::endl;
}
Test (const Test& t) :
iItem (t.iItem)
{
std::cout << "This is the copy ctor" << std::endl;
}
~Test()
{
std::cout << "This is the dtor" << std::endl;
}
const Test& operator=(const Test& t)
{
iItem = t.iItem;
std::cout << "This is the assignment operator" << std::endl;
return *this;
}
private:
int iItem;
};
int main()
{
{
Test t1;
Test t2 = t1;
}
{
Test t1;
Test t2 (t1);
}
{
Test t1;
Test t2;
t2 = t1;
}
}
This results in the following output (just added empy lines to make it more understandable):
doronw#DW01:~$ ./test
This is the default ctor
This is the copy ctor
This is the dtor
This is the dtor
This is the default ctor
This is the copy ctor
This is the dtor
This is the dtor
This is the default ctor
This is the default ctor
This is the assignment operator
This is the dtor
This is the dtor
The second and third set behave as expected, but in the first set the copy constructor is called even though the assignment operator is used.
Is this behaviour part of the C++ standard or just a clever compiler optimization (I am using gcc 4.4.1)
No assignment operator is used in the first test-case. It just uses the initialization form called "copy initialization". Copy initialization does not consider explicit constructors when initializing the object.
struct A {
A();
// explicit copy constructor
explicit A(A const&);
// explicit constructor
explicit A(int);
// non-explicit "converting" constructor
A(char const*c);
};
A a;
A b = a; // fail
A b1(a); // succeeds, "direct initialization"
A c = 1; // fail, no converting constructor found
A d(1); // succeeds
A e = "hello"; // succeeds, converting constructor used
Copy initialization is used in those cases that correspond to implicit conversions, where one does not explicitly kick off a conversion, as in function argument passing, and returning from a function.
C++ standard 8.5/12
The initialization that occurs in
argument passing, function return,
throwing an exception (15.1), handling
an exception (15.3), and
brace-enclosed initializer lists
(8.5.1) is called copy-initialization
and is equivalent to the form
T x = a;
The initialization that occurs in new
expressions (5.3.4), static_cast
expressions (5.2.9), functional
notation type conversions (5.2.3), and
base and member initializers (12.6.2)
is called direct-initialization and is
equivalent to the form
T x(a);
Your first set is according to the C++ standard, and not due to some optimization.
Section 12.8 ([class.copy]) of the C++ standard gives a similar example:
class X {
// ...
public:
X(int);
X(const X&, int = 1);
};
X a(1); // calls X(int);
X b(a, 0); // calls X(const X&, int);
X c = b; // calls X(const X&, int);
The last line would be the one matching your case.
Two questions about the following piece of code:
template <class T> class A {
protected:
T j;
public:
A(T k) :j(k) {cout << *this;}
~A() { cout << *this; }
A(const A<T> &a) {
j = a.j;
cout << *this;
}
virtual void print() const {cout << j << ' ';}
friend ostream &operator << (ostream &os, const A<T> &a) {
a.print();
return os;
}
operator T() { return j;}
};
template <class T> class inherit:public A<T> {
T field;
public:
inherit(const T&t) :A<T>(t), field(1+t) {
cout << *this;
}
void print() const {
A<T>::print();
cout << field << ' ';
}
};
int main(){
inherit <int> b(3);
inherit <string> c("asdf");
string k="str";
c + k;//error no operator +
b + 5;//no error
}
Why does inherit <int> b(3); leads to the copy ctor of inherit? Why copy instead of making a new instance of inherit from scratch using the default ctor?
Why does b+5; leads to the conversion operator operator T() and why it doesn't happen with c+k?
Why does inherit <int> b(3); leads to the copy ctor of inherit? Why copy instead of making a new instance of inherit from scratch using the default ctor?
Firstly, it does not lead to the copy constructor and the instance is in fact made from scratch.
The default constructor was not used because you didn't call the default constructor. The default constructor would be called with empty argument list (except, in this case, you must also leave out the parenthesis to avoid the vexing parse):
inherit <int> b; // this would call the default constructor
If you pass an argument to the constructor, then a non-default constructor will be invoked. inherit <int> b(3); leads to a call to inherit(const T&) which in this template instance is inherit(const int&). It is not the copy constructor of inherit.
Why does b+5; leads to the casting operator operator T()
Because there is no operator+(const inherit<int>&, int) nor the analogous member function defined. Therefore, the overload resolution looks for alternatives to which the operands can be implicitly converted. It just so happens, that a built-in operator+(int, int) exists, and inherit<int> can implicitly be converted to A<int> (because it's a base) and A<int> can be converted to an int (because of the casting operator). And so, that operator ends up being called.
and why it doesn't happen with c+k?
Firstly, you cannot even instantiate inherit <string> because the constructor tries to add an int to the argument string, which has no valid overload.
Now, assuming that constructor was fixed so that inherit<string> can exist, c + k still doesn't seem to work. I suspect that's because the string needs more conversions than int because it's not a primitive and you've reached the maximum depth that a user-defined conversion sequence can have. You can explicitly cast inherit<string> to string to shorten the conversion sequence:
static_cast<std::string>(c) + k; // this works
Why does b+5; leads to the conversion operator operator T() and why it doesn't happen with c+k?
The compiler is complaining about a completely different piece of code. If you remove the + inside main(), you can see it still complains about an operator+:
http://melpon.org/wandbox/permlink/H3cUUaf8fSnbYDwA
The reason for this is on this line:
inherit(const T&t) :A<T>(t), field(1+t) {
you have 1 + t, where t is std::string. std::string has no operator+ for int, so this does not compile.
I wrote the following c++ code trying to understand copy elision in c++.
#include <iostream>
using namespace std;
class B
{
public:
B(int x ) //default constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob =5;
ob=6;
ob=7;
return 0;
}
This produces the following output:
Constructor called
Constructor called
Constructor called
I fail to understand why is the constructor being called thrice with each assignment to object ob.
B ob =5;
This uses the given constructor.
ob=6;
This uses the given constructor because there is not a B& operator=(int) function and 6 must be converted to type B. One path to do this is to temporarily construct a B and use it in the assignment.
ob=7;
Same answer as above.
I fail to understand why is the constructor being called thrice with each assignment
As I stated above you do not have a B& operator=(int) function but the compiler is happy to provide a copy assignment operator (i.e., B& operator=(const B&);) for you automatically. The compiler generated assignment operator is being called and it takes a B type and all int types can be converted to a B type (via the constructor you provided).
Note: You can disable the implicit conversion by using explicit (i.e., explicit B(int x);) and I would recommend the use of explicit except when implicit conversions are desired.
Example
#include <iostream>
class B
{
public:
B(int x) { std::cout << "B ctor\n"; }
B(const B& b) { std::cout << B copy ctor\n"; }
};
B createB()
{
B b = 5;
return b;
}
int main()
{
B b = createB();
return 0;
}
Example Output
Note: Compiled using Visual Studio 2013 (Release)
B ctor
This shows the copy constructor was elided (i.e., the B instance in the createB function is triggered but no other constructors).
Each time you assign an instance of the variable ob of type B an integer value, you are basically constructing a new instance of B thus calling the constructor. Think about it, how else would the compiler know how to create an instance of B if not through the constructor taking an int as parameter?
If you overloaded the assignment operator for your class B taking an int, it would be called:
B& operator=(int rhs)
{
cout << "Assignment operator" << endl;
}
This would result in the first line: B ob = 5; to use the constructor, while the two following would use the assignment operator, see for yourself:
Constructor called
Assignment operator
Assignment operator
http://ideone.com/fAjoA4
If you do not want your constructor taking an int to be called upon assignment, you can declare it explicit like this:
explicit B(int x)
{
cout << "Constructor called" << endl;
}
This would cause a compiler error with your code, since it would no longer be allowed to implicitly construct an instance of B from an integer, instead it would have to be done explicitly, like this:
B ob(5);
On a side note, your constructor taking an int as parameter, is not a default constructor, a default constructor is a constructor which can be called with no arguments.
You are not taking the assignment operator into account. Since you have not defined your own operator=() implementation, the compiler generates a default operator=(const B&) implementation instead.
Thus, your code is effectively doing the following logic:
#include <iostream>
using namespace std;
class B
{
public:
B(int x) //custom constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
B& operator=(const B &b) //default assignment operator
{
return *this;
}
};
int main()
{
B ob(5);
ob.operator=(B(6));
ob.operator=(B(7));
return 0;
}
The compiler-generated operator=() operator expects a B object as input, but you are passing an int value instead. Since B has a non-explicit constructor that accepts an int as input, the compiler is free to perform an implicit conversion from int to B using a temporary object.
That is why you are seeing your constructor invoked three times - the two assignments are creating temporary B objects.
Suppose I have a class A. I have defined a copy constructor and an assignment operator overloading function. When I do
Class A;
Class B=A;
Then while defining Class B, is the copy constructor invoked or the assignment operator?
Thanks in advance.
EDIT:
Sorry, I mentioned wrong code. It should be:
A a;
A b=a;
IIRC T t = value invokes the copy constructor, you can verify that by outputting a string in the constructors to determine which method is used. IIRC when the declaration and assignment are on the same line, it is not called assignment but initialization.
On the other hand, what you've posted does not make sense, you cannot assign one type to another type, you can only assign to type instances.
EDIT: Even if you have a case of two different types (the context of your question is not clear on this one):
class A {};
class B {
public:
B(const A& other) { cout << "copy"; }
B& operator=(const A& other) { cout << "assign"; }
};
int main() {
A a;
B b = a; // copy con
B b1(a); // same as above
b = a; // assign op
}
Even then, when both the "copy constructor" and assignment operators take in another type, the copy constructor will still be invoked rather than the assignment operator.
Assuming you actually mean something like:
A a;
A b = a;
The copy constructor is invoked. The Standard allows = this special meaning in this usage.
Create a simple class with both, and debug what function is executed by setting a breakpoint in both. Then youll see, and youll also learn a little bit of debugging.
Let's try it out!
#include <iostream>
class A {
public:
A() {
std::cout << "default constructor\n";
}
A(const A& other) {
std::cout << "copy constructor\n";
}
A& operator=(const A& rhs) {
std::cout << "assignment operator\n";
return *this;
}
};
int main(int argc, char** argv) {
std::cout << "first declaration: ";
A a;
std::cout << "second declaration: ";
A b(a);
std::cout << "third declaration: ";
A c = a;
std::cout << "fourth declaration: ";
A d;
std::cout << "copying? ";
d = a;
return 0;
}
This prints:
first declaration: default constructor
second declaration: copy constructor
third declaration: copy constructor
fourth declaration: default constructor
copying? assignment operator
Working example here: http://codepad.org/DNCpqK2E
when you are defining a new object with assigning another object into it. It invokes copy constructor.
e.g,
Copy constructor call:
Class A;
Class B=A;
Assignment operator call:
Class A;
Class B;
B=A;
You can always test this, by writing a "print" statement in both the methods to find out which one is being called.
Hope it helped...
Consider the following code.
#include <iostream>
using namespace std;
class Test
{
private:
int x,y;
public:
Test () {
cout <<" Inside Constructor "<<endl;
x=100;
}
explicit Test (const Test & t)
{
cout <<"Inside Copy Constructor "<<endl;
x = t.x;
}
void display()
{
cout <<" X is "<<x<<endl;
}
};
int main (int argc, char ** argv){
Test t;
t.display();
cout <<"--- Using Copy constructor "<<endl;
Test t2(t);
t2.display ();
Test t3=t2;
t3.display ();
}
Test (const Test & t) -> is a copy constructor
Question:
Is the same used as a "Conversion Operator" ?
Test t3 = t2 [ Here copy Constructor is treated as a conversion operator]
I am not sure if my understanding is correct?. Kindly correct me if i am wrong?
Test t3=t2;
Should never compile, if copy c-tor is explicit.
n3337 12.3.1/3
A non-explicit copy/move constructor (12.8) is a converting constructor. An implicitly-declared copy/move
constructor is not an explicit constructor; it may be called for implicit type conversions.
This quote appears to following question: Implicit copy constructor
So, in your case, it's not conversion constructor.
In C++, the term conversion implies two different types : source type and destination type.
Copy-constructor, by definition, involves only one type : source type and destination type are same. So it cannot be called a conversion function.
when you use T t3 = t2. It will call the assignment operator which you haven't define it.