I have question on the below code. In the main function what will happen when the line: obj = 20; is executed. I am not able to understand why it calls the constructor? Could anyone of you please explain?
#include <iostream>
#include <string>
using namespace std;
class Int {
int x;
public:
Int(int x_in = 0)
: x{ x_in }
{
cout << "Conversion Ctor called" << endl;
}
operator string()
{
cout << "Conversion Operator" << endl;
return to_string(x);
}
};
int main()
{
Int obj(3);
string str = obj;
obj = 20;
string str2 = static_cast<string>(obj);
obj = static_cast<Int>(30);
return 0;
}
Within the class there is not defined the assignment operator operator =( int ). But the class has the conversion constructor
Int(int x_in = 0)
So in this statement
obj = 20;
there is called the constructor like Int( 20 ) to convert the integer value to an object of the type Int that can be assigned to the object obj due to the implicit move assignment operator generated by the compiler.
Lacking a assignment operator taking int, your compiler uses the next best assignment operator it can get it's hands on, which is the implicitly declared move assignment operator (Int::operator=(Int&&)). To use this operator, a rvalue reference to a Int object is required, which the compiler creates using the constructor Int::Int(int), i.e. the compiler treats obj = 20; as
obj.operator=(Int(20));
To see what's happening here, you could implement the move assignment operator yourself to print something to the console when the assignment operator is executed:
class Int
{
...
public:
...
Int& operator=(Int&& other)
{
std::cout << "move assignment of Int, new value: " << other.x << '\n';
x = other.x;
return *this;
}
// the following members are only declared to make sure the available
// constructors/operators are the same as in the original version of the code
Int(Int&&) = default;
Int& operator=(Int const&) = default;
Int(Int const&) = default;
};
Related
In my buggy class, I'm only exposing a constant version of MyStruct, experimenting with initializing a constant reference to the private member in an initializer list.
The program I'm debugging is functionally equivalent to the following:
#include <iostream>
#include <optional>
struct MyStruct {
int member = 1;
};
class MyType {
MyStruct struct_member_;
public:
MyType() : struct_member(struct_member_) {}
MyType& operator =(const MyType& other_side) {
struct_member_ = other_side.struct_member_;
return *this;
};
const MyStruct& struct_member;
void test() const {
std::cout << "Why isn't " << &struct_member << " the same as " << &struct_member_ << std::endl;
}
};
int main()
{
std::optional<MyType> my = MyType();
my.value().test();
std::optional<MyType> yours = MyType();
yours.value().test();
my = yours;
my.value().test();
my = MyType();
my.value().test();
return 0;
}
For this program, here's the output:
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
Why isn't 0x7ffeefbff868 the same as 0x7ffeefbff878
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
Why isn't 0x7ffeefbff890 the same as 0x7ffeefbff8a0
However, in the program I'm debugging, struct_member_ and struct_member are getting desynchronized (either the const reference struct_member is getting assigned to a different place in memory-- except it's const, or it's loosing track with an updated struct_member_-- except its memory address shouldn't change?) and I'm not sure which or why.
Any ideas on what could lead to this happening, or tips to make this pattern work with non-POD types? (I plan to be transitioning to method-based accessors anyway, since this experiment seems to be failing.)
Turns out optionals and copy constructors were key to all of this. The copy constructor was defaulting and I didn't realize it. Funny, because the compiler warned that I needed a non-default operator=, but didn't afford me the same warning for the copy constructor.
class MyType {
MyStruct struct_member_;
public:
MyType() : struct_member(struct_member_) {
std::cout << "constructor" << std::endl;
}
MyType(const MyType& other) : struct_member(struct_member_) {
std::cout << "copy constructor " << std::endl;
struct_member_ = other.struct_member_;
};
MyType& operator =(const MyType& other_side) {
std::cout << "assignment operator called" << std::endl;
struct_member_ = other_side.struct_member_;
return *this;
};
const MyStruct& struct_member;
void test() const {
std::cout << "Why isn't " << struct_member.member << ": " << &struct_member << " the same as " << &struct_member_ << std::endl;
}
};
Yields the correct output:
constructor
copy constructor
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
constructor
copy constructor
Why isn't 0x7ffeefbff878 the same as 0x7ffeefbff878
assignment operator called
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
constructor
assignment operator called
Why isn't 0x7ffeefbff8a0 the same as 0x7ffeefbff8a0
Altogether, it'd be less hassle just to expose getters as methods.
Either delete the copy constructor (because the default behavior binds the reference to the "wrong" thing in this case):
MyType(MyType const&) = delete;
Or provide a copy constructor that does the right thing, by binding the public const accessor to the self-same object:
MyType(MyType const& other)
: struct_member_{other.struct_member_}
, struct_member(struct_member_) {}
The output is
Constructor called
20
When I am adding a copy-constructor, it is giving error "invalid initialization of non-const reference of type ‘Foo&’ from an rvalue of type ‘Foo’ "
#include <iostream>
using namespace std;
class Foo
{
int a;
public:
Foo(int a)
{
this->a =a;
cout<<"Constructor called\n";
}
void operator=(Foo f)
{
this->a = a;
cout<< "Assignment operator called";
}
void show()
{
cout<<this->a<<endl;
}
};
int main()
{
// your code goes here
Foo F1 = static_cast<Foo>(20);
F1.show();
return 0;
}
There is no assignment in the code you posted. This:
Foo F1 = static_cast<Foo>(20);
is alternate syntax for copy construction, and is an initialisation, not an assignment.
Your problem with the copy constructor is probably caused by you defining it as
Foo( Foo & f );
which prevents it from binding to temporary values. It should be:
Foo( const Foo & f );
I have declared a Point class like this :
class Point{
private :
int a,b;
public :
Point(Point const &p) {
a = p.a + 1;
b = 0;
}
Point(){a=2; b=3;}
int getX(){return a;}
int getY(){return b;}
};
int main(){
Point p1,p2;
p2=p1;
cout << p2.getX(); // 2
cout << p2.getY(); // 3
}
Why the copy constructor is not called ? as it's called here :
int main(){
Point p1;
Point p2=p1;
cout << p2.getX(); // 3
cout << p2.getY(); // 0
}
This is copy construction
Point p2=p1; // p2 is constructed here.
// This is shorthand for Point p2(p1);
This is assignment
p2=p1; // p2 already exists (it was created on the previous line).
The assignment operator is defined with:
// If you don't define this the compiler will generate one for you.
Point& operator=(Point const& rhs)
{
// Copy for rhs into this.
return *this;
}
// The compiler generated one looks like this:
Point& operator=(Point const& rhs)
{
a = rhs.a;
b = rhs.b;
return *this;
}
In the first program
int main(){
Point p1,p2;
p2=p1;
^^^^^
there is called the copy assignment operator created by the compiler implicitly.
In this program object p2 was already created using the default constructor
Point p1,p2;
In tfhe second program
int main(){
Point p1;
Point p2=p1;
^^^^^^^^^^^
there is indeed called the copy constructor.
Point p1,p2;
p2=p1;
p2 is already constructed so the second statement invokes the assignment operator
Point p1;
Point p2=p1;
Here p2 is copy-constructed since it had not been constructed before.
Consider this code:
#include <iostream>
class A {
public:
A() { std::cout << "Ctor called\n"; }
A(const A&) { std::cout << "Copy Ctor called\n"; }
A& operator=(const A&) { std::cout << "Assignment operator called\n"; return *this;}
};
int main() {
A a,b;
b = a;
A c;
A d = c;
}
the output of which is enlightening:
Argento:Desktop marinos$ clang++ test.cpp -o test
Argento:Desktop marinos$ ./test
Ctor called
Ctor called
Assignment operator called
Ctor called
Copy Ctor called
If I modify the assignment opreator so that it returns an object A instead of a reference to an object A then something funny happens.
Whenever the assignment operator is called, the copy constructor is called right afterwards. Why is this?
#include <iostream>
using namespace std;
class A {
private:
static int id;
int token;
public:
A() { token = id++; cout << token << " ctor called\n";}
A(const A& a) {token = id++; cout << token << " copy ctor called\n"; }
A /*&*/operator=(const A &rhs) { cout << token << " assignment operator called\n"; return *this; }
};
int A::id = 0;
A test() {
return A();
}
int main() {
A a;
cout << "STARTING\n";
A b = a;
cout << "TEST\n";
b = a;
cout << "START c";
A *c = new A(a);
cout << "END\n";
b = a;
cout << "ALMOST ENDING\n";
A d(a);
cout << "FINAL\n";
A e = A();
cout << "test()";
test();
delete c;
return 0;
}
The output is as follows:
0 ctor called
STARTING
1 copy ctor called
TEST
1 assignment operator called
2 copy ctor called
START c3 copy ctor called
END
1 assignment operator called
4 copy ctor called
ALMOST ENDING
5 copy ctor called
FINAL
6 ctor called
test()7 ctor called
Because if you don't return a reference of the object it makes a copy.
As #M.M said about the final test() call, the copy does not appears because of the copy elision What are copy elision and return value optimization?
I have written following class which has overloaded assignment operator. As shown in example everywhere I returned *this from assignment operator.
class Sample
{
int *p;
int q;
public:
Sample()
{
cout<<"Constructor called"<<endl;
p = new int;
q = 0;
}
Sample& Sample::operator =(const Sample &rhs)
{
cout<<"Assignment Operator"<<endl;
if(this != &rhs)
{
delete p;
p = new int;
*p = *(rhs.p);
}
return *this;
}
void display()
{
cout<<"p = "<<p<<" q = "<<q<<endl;
}
};
When I call assignment operator like a = b, it goes like, a.operator=(b);.
Now I am calling a's operator function, this is already being passed with operator = then why it is required to return it from assignment operator?
You have to return *this (and also by reference) if you want to support chaining of assignment. For e.g
Class A
{
};
A x,y,z,w;
x = y = z = w; //For this you are returning *this.
EDITED FOR MORE CLARIFICATION:- ( In response to your comment )
Let's suppose you're not returning anything from your assignment operator then expression will be evaluated as follows:-
x=y=z => x=(y=z)
Above will result into a call to
y.operator(z)
as assignment operator is right associative.
After this next call would be to
x.operator ( value returned from y=z) ).
If you don't return any value chaining would fail.
Hope I am clear
You're returning it to allow for chaining, you can't chain an assignment sequence without returning a reference to Sample, perhaps this will make it more clear:
int count = 0;
class Sample {
int *p;
int q;
int m_count;
public:
Sample() {
m_count = count;
cout<<"Constructor called for m_count = "<< count++ << endl;
p = new int;
q = 0;
}
Sample& operator =(const Sample &rhs) {
cout<<"Assignment Operator (m_count " <<
m_count << " = m_count " << rhs.m_count << ") " <<endl;
if(this != &rhs)
{
delete p; // Unnecessary
p = new int; // Unnecessary
*p = *(rhs.p);
}
return *this;
}
};
int main() {
Sample a;
Sample b;
Sample c;
// [b = c] will return a Sample& to the "changed" b
a = b = c;
}
Example
Counter-example with void return value:
int count = 0;
class Sample {
int *p;
int q;
int m_count;
public:
Sample() {
m_count = count;
cout<<"Constructor called for m_count = "<< count++ << endl;
p = new int;
q = 0;
}
void operator =(const Sample &rhs) {
cout<<"Assignment Operator (m_count " <<
m_count << " = m_count " << rhs.m_count << ") " <<endl;
if(this != &rhs) {
delete p; // Unnecessary
p = new int; // Unnecessary
*p = *(rhs.p);
}
}
};
int main() {
Sample a;
Sample b;
Sample c;
a = b; // Valid
a = b = c; // Not valid - error: no viable overloaded '='
}
An assignment statement,
a = b;
Requires that b should an R-value, and a must be an L-value. When you change the assignment as:
a=foo();
The expression foo(), that is the function call to foo must result in an R-value. If foo returns void, it doesn't produce R-value (or any value). Therefore, foo is required to return a value (Via a explicit return statement(s)). That's the language mandate!
The b, in first statement may be L-value also. For example:
a = b = c;
The variable b is both L-value (for b=c), as well as R-value (for a=b). When operator= returns T&, it may act as L-value (as well as R-value). But when operator= returns const T&, it may only be R-value. Therefore, if a class returns a const reference, following wont work:
a = b = c;
Here, c is assigned to a (in the overload itself), but b is a const (R-value only). It won't allow a=b.
Its mainly to support assignment chaining.
Sample A,B,C;
A=B=C;
You can have a look into the existing questions:
Why should the assignment operator return a reference to the object?
Why must the copy assignment operator return a reference/const reference?