Implementing the copy constructor in terms of operator=

后端 未结 8 1921
自闭症患者
自闭症患者 2020-12-28 16:19

If the operator= is properly defined, is it OK to use the following as copy constructor?

MyClass::MyClass(MyClass const &_copy)
{
    *this          


        
相关标签:
8条回答
  • 2020-12-28 16:38

    If all members of MyClass have a default constructor, yes.

    Note that usually it is the other way around:

    class MyClass
    {
    public:
        MyClass(MyClass const&);     // Implemented
        void swap(MyClass&) throw(); // Implemented
        MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
    };
    

    We pass by value in operator= so that the copy constructor gets called. Note that everything is exception safe, since swap is guaranteed not to throw (you have to ensure this in your implementation).

    EDIT, as requested, about the call-by-value stuff: The operator= could be written as

    MyClass& MyClass::operator=(MyClass const& rhs)
    {
        MyClass tmp(rhs);
        tmp.swap(*this);
        return *this;
    }
    

    C++ students are usually told to pass class instances by reference because the copy constructor gets called if they are passed by value. In our case, we have to copy rhs anyway, so passing by value is fine.

    Thus, the operator= (first version, call by value) reads:

    • Make a copy of rhs (via the copy constructor, automatically called)
    • Swap its contents with *this
    • Return *this and let rhs (which contains the old value) be destroyed at method exit.

    Now, we have an extra bonus with this call-by-value. If the object being passed to operator= (or any function which gets its arguments by value) is a temporary object, the compiler can (and usually does) make no copy at all. This is called copy elision.

    Therefore, if rhs is temporary, no copy is made. We are left with:

    • Swap this and rhs contents
    • Destroy rhs

    So passing by value is in this case more efficient than passing by reference.

    0 讨论(0)
  • 2020-12-28 16:41

    While the end result is the same, the members are first default initialized, only copied after that.

    With 'expensive' members, you better copy-construct with an initializer list.

    struct C {
       ExpensiveType member;
    
       C( const C& other ): member(other.member) {}
    };
    
    
    
     };
    
    0 讨论(0)
  • 2020-12-28 16:41

    I would say this is not okay if MyClass allocates memory or is mutable.

    0 讨论(0)
  • 2020-12-28 16:43

    yes.

    personally, if your class doesn't have pointers though I'd not overload the equal operator or write the copy constructor and let the compiler do it for you; it will implement a shallow copy and you'll know for sure that all member data is copied, whereas if you overload the = op; and then add a data member and then forget to update the overload you'll have a problem.

    0 讨论(0)
  • 2020-12-28 16:44

    It is more advisable to implement operator= in terms of an exception safe copy constructor. See Example 4. in this from Herb Sutter for an explanation of the technique and why it's a good idea.

    http://www.gotw.ca/gotw/059.htm

    0 讨论(0)
  • 2020-12-28 16:44

    It is technically OK, if you have a working assignment operator (copy operator).

    However, you should prefer copy-and-swap because:

    • Exception safety is easier with copy-swap
    • Most logical separation of concerns:
      • The copy-ctor is about allocating the resources it needs (to copy the other stuff).
      • The swap function is (mostly) only about exchanging internal "handles" and doesn't need to do resource (de)allocation
      • The destructor is about resource deallocation
      • Copy-and-swap naturally combines these three function in the assignment/copy operator
    0 讨论(0)
提交回复
热议问题