jeudi 3 septembre 2015

returning constant object and assigning it to non-constant object

I've found strange behavior of a code which is apparently ignoring const-ness:

#include <iostream>

using std::cerr;

class A
{
public:
    A() { cerr << "A::A()\n"; }
    A(const A &a) { cerr << "A::A(const A&)\n"; }
    A(A &&) { cerr << "A::A(A&&)\n"; }
    A & operator = (const A &a) { cerr << "A::operator=(const A&)\n"; return *this; }
    A & operator = (A &&a) { cerr << "A::operator(A&&)\n"; return *this; }
    ~A() { cerr << "A::~A()\n"; }

    const A get() const { cerr << "const A A::get() const\n"; return A(); }
    A get() { cerr << "A A::get()\n"; return A(); }
};

int main()
{
    const A a;
    A b = a.get();
}

Firstly, what I did expect here: a is a constant, so the constant-version of get() is invoked. Next, constant object is being returned, but on the left side is non-constant object b, so the copy-constructor is ought to be called. Which is not:

A::A()
const A A::get() const
A::A()
A::~A()
A::~A()

Is this behavior expected by c++ standard? So, is it okay that constness of a temporary object is simply ignored by RVO? And how copying could be enforced here?

Output with copy-elision disabled (-fno-elide-constructors) makes an additional move and the expected copy-constructor call:

A::A()
const A A::light_copy() const
A::A()
A::A(A&&)
A::~A()
A::A(const A&)
A::~A()
A::~A()
A::~A()

If a object is not constant, then it will be two moves without copying, which is expected too.

PS. The behavior matters for me because the one I see is breaking shallow-copying const-strictness: for const-version of get() (which is shallow_copy() actually) I need to be sure that no modification of the returned object will be made, because the returned object is a shallow copy and a modification on the shallow copy will affect the "parent" object (which might be a constant).

Aucun commentaire:

Enregistrer un commentaire