Search code examples
c++gccconst-referencecopy-assignmentmove-assignment-operator

Why GCC refuses a const reference within a copy-assignment operation?


I want to overload a common copy-assignment operator normally. At first I used a interface that only requires a const reference to the source, and explicitly disabled the interface that accepts a modifiable reference, but I can not pass the compilation. The compiler reports "error: use of deleted function ‘ClassA& ClassA::operator=(ClassA&)"

Of course, I can get compiled if I don't expicitly delete the interface, but that is not my purpose. I'd like to explicitly delete it, to avoid unexpected using it.

Why a copy-assignment operation needs a modifiable reference to the source, instead of a const reference? The assignment operation just needs to access the source read-only!

There is a same question about the copy-constructor, I omit it for simplifying.

What's wrong with my code? or we can NOT delete it?

My sample code is following:

class ClassA {
public:
   ClassA() = default;
   ClassA( ClassA & ) = default;

   ClassA & operator=( ClassA & )
   = delete   // Must comment-out this, or we can't pass the compilation.
   // { cout << "ClassA & operator=( ClassA & ) executed." << endl; return *this; }
   ;

   ClassA & operator=( ClassA && ) {
      cout << "ClassA & operator=( ClassA && ) executed." << endl;
      return *this;
   };

   ClassA & operator=( const ClassA & ) {
      cout << "ClassA & operator=( const ClassA & ) executed." << endl;
      return *this;
   };
   ClassA & operator=( const ClassA && ) {
      cout << "ClassA & operator=( const ClassA && ) executed." << endl;
      return *this;
   };
};

int main() {
   ClassA oa, ob;
   ob = oa;

   return EXIT_SUCCESS;
};

Solution

  • or we can NOT delete it?

    You just don't need to do that. If you provide a user-defined copy assignment operator, then no other ones will be implicitly-declared, i.e. only the user-defined one will exist.

    If you do that, the copy assignment operator you explicitly marked as delete will participate in overload resolution; when it's selected the compilation fails. For ob = oa;, the operator=( ClassA & ) is a better match, if it doesn't exist, operator=( const ClassA & ) will be used and work fine.

    So in this case you can just do

    class ClassA {
    public:
    
       ClassA & operator=( ClassA && ) {
          cout << "ClassA & operator=( ClassA && ) executed." << endl;
          return *this;
       }
    
       ClassA & operator=( const ClassA & ) {
          cout << "ClassA & operator=( const ClassA & ) executed." << endl;
          return *this;
       }
    };