I'll tell you why that conversion operator happens to be there. Well, look at this example:
struct A;
struct B {
explicit B(A&a):a(a){ }
A &a;
};
struct A {
A() { }
A(B b){ move_from(a); }
A(A &a) { move_from(a); }
operator B() { return B(*this); }
void move_from(A &a) {
std::cout << "A::A(@" << &b.a << ")" << std::endl;
}
};
int main() {
A a = A();
}
We have move semantics for our class A: In its copy constructor, we want to "steal" away some stuff from the other instance. For auto_ptr, that is the pointer that is managed, for us we just output a message instead. What is important is that we can't use a usual copy constructor:
A(A const& a) {
/* oops, a is const, we can't steal something from it! */
}
But if we change that to A(A &a)
, we won't be able to construct from a by-value/temporary A: Those can't be bound to a reference-to-nonconst:
A(A &a) {
}
...
A a = A(); // fail, because A &a = A() doesn't work
auto_ptr and our A class uses the trick that non-const member functions can still be called on temporaries/by-value A's. That is, we could also have written:
struct A {
...
B get_b() { return B(*this); }
...
};
...
A a = A().get_b();
But that works, we don't want to be bothered with that, of course. We want that it just works to assign a A()
or the return value of a function returning an A
by-value. So what auto_ptr and our A class uses is a conversion operator, which automatically figures out that when A is converted to B, then we could construct a A instance using the B we created temporarily.