Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does assignment operator call constructor?

I am just playing around to understand smart pointers and trying to make mine but I come across a situation that I do not fully understand. Here is the code:

#include <iostream>
template <class T>
class Holder
{
private:
        T * obj;
public:
        Holder(T * tt) : obj(tt) 
        {
                std::cout << "ctor : " << tt->dummy << std::endl;
        }
        T * operator -> ()
        {
                return obj;
        }
        operator bool()
        {
                return obj;
        }
        T * const get() const
        {
                return obj;
        }
        void reset() {swap(0);}
        void swap(T * other)
        {
                obj = other;
        }
        Holder & operator = (const Holder& holder)
        {
                obj = holder.get();
                return *this;
        }
        Holder(const Holder & holder) : obj(holder.get()) {} 
};

class A
{
public:
        int dummy;
        A(int a) : dummy(a) {}
};

int main ()
{
        A * a = new A(1);
        Holder<A> holder(a);
        A * b = new A(2);
        holder = b;

        std::cout << holder->dummy << std::endl;

        return 0;
} 

The code compiles and on the line of holder = b; the constructor of Holder class is called. I thought compiler would give an error. It is not the assingment operator but why is it calling constructor?

like image 423
ali_bahoo Avatar asked Dec 08 '10 00:12

ali_bahoo


3 Answers

holder = b attempts to assign from b to Holder. b is of type A*, and holder is of type Holder<A>.

The Holder template defines assignment from another instance of the same Holder type, so the compiler looks for a conversion from A* to Holder<A>. It finds the constructor, and uses that.

Constructors which may take exactly one argument may be used for implicit conversions, unless you tag them with the explicit keyword.

like image 113
Karl Knechtel Avatar answered Nov 19 '22 06:11

Karl Knechtel


Both the constructor and assignment operator are called. You can check this by printing something in operator =.

This happens because operator = is defined to take a const Holder &, but b is of type A *. So first the Holder(T *) constructor is called to create a temporary object, then this object is assigned to holder through operator =.

If you define an operator =(const T *), only the assignment operator will be called.

like image 38
casablanca Avatar answered Nov 19 '22 05:11

casablanca


I do not see a version of the assignment operator that takes a right hand side of A*

    A*        a        = new A(1);
    Holder<A> holder(a);
    A*        b         = new A(2);

    // assigning object of type A* to Holder<A>
    holder = b;

    // No appropriate assignment operator provide.
    // But a constructor is available to convert RHS parameter to correct type.
    // So compiler generates the following code:

    holder = Holder<A>(b);

    // There is an appropriate assignment operator for this.
    // So it compiles. 
like image 2
Martin York Avatar answered Nov 19 '22 05:11

Martin York