Franck Freiburger
Franck Freiburger

Reputation: 28538

g++ and non-const copy constructor issue

Is it possible to tell g++ to use the FOO& operator when constructing the FOO object ?

struct FOO {

        FOO( FOO & foo ) { // non-const copy constructor
        }

        operator FOO&() {

                return *this;
        }

        FOO( int i ) {
        }
};


int main() {

        FOO a(FOO(5));
}

I currently get the following error:

In function int main():
  error: no matching function for call to FOO::FOO(FOO)
  note: candidates are: FOO::FOO(int)
  note:                 FOO::FOO(FOO&)

-- edit --

Note that I try to setup an object that can exchange the ownership of a resource.
Calling FOO foo1(foo) make foo to lose the ownership of the resource, this mean that foo cannot be const.
Also note that I want to avoid smart-pointer mechanism.

Upvotes: 1

Views: 480

Answers (2)

Xeo
Xeo

Reputation: 131907

Your conversion operator will never be picked up.

§12.3.2 [class.conv.fct] p1

A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.

The reason is that the conversions mentioned here (except to cv void) are already done by so-called standard conversions (qualification conversion (adding const or volatile) and identity conversion (binding an object to a reference)) and standard conversions are always preferred to user-defined conversions:

§13.3.3.2 [over.ics.rank] p2

a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence [...]


For your specific case, if you want to transfer ownership, do so in C++11 style, with a move constructor.

#include <utility> // move

struct foo{
  int resource;
  foo(int r)
    : resource(r) {}
  foo(foo&& other)
    : resource(other.resource)
  { other.resource = 0; }
};

int main(){
  foo f1(foo(5));
  //foo f2(f1); // error
  foo f3(std::move(f1)); // OK
}

Transferring ownership via non-const copy constructors is a very bad idea, as such a type can never be stored in standard containers, see the ugly std::auto_ptr (replaced by std::unique_ptr in C++11, which has proper move semantics).

Upvotes: 3

Mike DeSimone
Mike DeSimone

Reputation: 42845

Note that I try to setup an object that can exchange the ownership of a resource.

Calling FOO foo1(foo) make foo to lose the ownership of the resource, this mean that foo cannot be const.

Also note that I want to avoid smart-pointer mechanism.

So you've got something like:

struct FOO {
        // ...
        SomeType* storage;
        bool owns_storage;
        // ...
        FOO(const FOO& foo): storage(foo.storage), owns_storage(true) {
            foo.owns_storage = false; /* <-- fails to build */ }
        ~FOO() { if(owns_storage) delete storage; }
};

And you need a copy to set owns_storage to false on the const original object. Use the mutable keyword and your problem goes away:

struct FOO {
        // ...
        SomeType* storage;
        mutable bool owns_storage;
        // ...
        FOO(const FOO& foo): storage(foo.storage), owns_storage(true) {
            foo.owns_storage = false; /* builds fine now */ }
        ~FOO() { if(owns_storage) delete storage; }
};

Upvotes: 1

Related Questions