Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the compiler remove const from my const copy?

Tags:

c++

There's still something wrong with my thinking about CV-qualifiers. Let me explain ...

Until today, my mental model was: the compiler can get rid of qualifiers by creating a copy. The return value of the copy assignment operator is not CV-qualified. And once it has a CV-unqualified type, it can then make it more CV-qualified.

Basically like this:

Adding and removing const

If an object is not copyable, you can't get rid of the CV-qualifiers, e.g.

#include <fstream>
  
int main()
{
    std::ifstream file("example.txt");
    std::ifstream const ccopy = file; // error: attempting to reference a deleted function
  
    std::ifstream const cfile("example.txt");
    std::ifstream copy = cfile;  // error: attempting to reference a deleted function
}

With this in mind, I created the following code, which has a modified copy assignment operator that returns a const C instead of a normal C. In my mind, the compiler can't make a CV-unqualified copy any more. The copy would now be const. Thus, in my mind, it can't assign the returned const C to the non-const C c variable.

#include <iostream>
class C{
    public:
    C()
    {}

    C([[maybe_unused]] C const& other )
    {
        std::cout << "copy constructor\n";
    }

    const C operator=([[maybe_unused]] C const&  other){   // note const return type
        std::cout << "copy assignment\n";
        return C{};
    }
};
int main()
{
    const C cc;
    C c;
    c = cc;    // I expected this to not work
}

Compiler Explorer

It also doesn't use the copy constructor to create another copy. The output is only:

copy assignment

Why is it still possible to assign the const C copy to the non-const variable C c?

like image 301
Thomas Weller Avatar asked Oct 24 '25 14:10

Thomas Weller


1 Answers

The expression c = cc doesn't mean "rebind the name c to the object returned by the operator=", as you seem to believe. Instead, it means c.operator=(cc) i.e. call C::operator= passing a pointer to object c as the implicit this parameter, and passing reference to object cc as the other parameter.

So, the return type of C::operator= is completely irrelevant. You can even declare it as void [Compiler Explorer] and it still compiles.

If you were using the return value, then it would not compile [Compiler Explorer] due to dropping qualifiers:

/* your class definition here */

void useit(C&) // no const here
{}

int main()
{
    const C cc;
    C c;
    useit(c = cc); // GCC error: cannot bind non-const lvalue reference of type 'C&' to an rvalue of type 'const C'
}
like image 93
yuri kilochek Avatar answered Oct 27 '25 03:10

yuri kilochek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!