1

To understand constructor and assignment, I wrote a very simply testing code like this:

class A { public: A() { std::cout<<"This is default cstr."; } A(int i) { std::cout<<"This is int cstr. value is "<<i; } A(const A &a) { std::cout<<"This is copy cstr."; } A operator=(const A &a) { std::cout<<"This is assignment operator."; return *this;// this line is tricky } }; int _tmain(int argc, _TCHAR* argv[]) { std::cout<<"line 1 "; A a1; std::cout<<std::endl; std::cout<<"line 2 "; A a2 = A(1); std::cout<<std::endl; std::cout<<"line 3 "; a1 = a2; std::cout<<std::endl; return 0; } 

For line 3 I got:

line 3 This is assignment operator.This is copy cstr. 

But if I change return *this; to return NULL, I got:

line 3 This is assignment operator.This is int cstr. value is 0 

Could someone explain what happened inside for me?

3 Answers 3

1

Your operator is returning A instead of A&:

A operator=(const A &a) 

So when you return NULL, you are calling the implicit constructor A(int) and passing NULL to it.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! So every non-reference return will call the copy cstr once?
No, you're missing the point. The assignment operator is supposed to return a reference. And a reference cannot be NULL. You should have declared your A(int) constructor as explicit A(int), and the compiler would have generated an error. The behaviour you were getting is almost always due to an unintentional mistake.
1

The problem

line 3 This is assignment operator.This is copy cstr. 

Your code's calling:

A operator=(const A &a) { std::cout<<"This is assignment operator."; return *this; 

This obviously prints "This is assignment operator.", then return *this; statement sees the return type of A and creates a return value of type A doing the equivalent of A(*this); -> that calls the copy constructor, explaining this part of the output:

line 3 This is assignment operator.This is copy cstr. ^^^^^^^^^^^^^^^^^^ 

But if I change return *this; to return NULL, I got:

line 3 This is assignment operator.This is int cstr. value is 0 

In this case:

A operator=(const A &a) { std::cout<<"This is assignment operator."; return NULL; } 

You end up creating the return value of type A as per A(NULL), and as NULL is 0, that matches the A(int) constructor best, which is why you see:

line 3 This is assignment operator.This is int cstr. value is 0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

The solution

A& operator=(const A &a) { std::cout<<"This is assignment operator."; return *this; } ^ 

You normally want the assignment operator to return a reference to the *this object. That way, no additional A object is constructed as the assignment operator function returns.

Aside - why return `A&` anyway?

The reason A& is returned and not void, is that it allows further chained use of the object, as in:

a1 = a2 = a3; 

Which is evaluated as:

a1.operator=(a2.operator=(a3)); 

Is a2.operator= returned void then there'd be no usable argument to a1.operator=().

A non-const reference supports usage like:

make_uppercase(my_string = other_string); 

In some other languages, that would need to be broken into two statements. Whether you wish it was depends on whether you find it confusing, and how much you value concision.

Comments

0

Your code says

A operator = (const A& a) 

You take a reference to an A, you modify yourself, and then you return A(*this) which invokes the copy-constructor to create a new instance and return by value.

What you probably intended was

A& operator = (const A& a) 

This will then return a reference to *this rather needing to copy it into a new temporary instance.

Be aware that NULL is a macro alias for '0UL' or '0ULL' which the compiler detects as being a match for A(int). This is one of the reasons that C++11 introduced nullptr as an alternative to NULL.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.