Я скажу вам , почему этот оператор преобразования там оказался. Ну, посмотрите на этот пример:
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();
}
У нас есть семантика перемещения для нашего класса A: в его конструкторе копирования мы хотим «украсть» некоторые вещи из другого экземпляра. Для auto_ptr это управляемый указатель, для нас мы просто выводим сообщение вместо этого. Важно то, что мы не можем использовать обычный конструктор копирования:
A(A const& a) {
/* oops, a is const, we can't steal something from it! */
}
Но если мы изменим это на A(A &a)
, мы не сможем построить из значения / временного A: Они не могут быть привязаны к ссылке на nonconst:
A(A &a) {
}
...
A a = A(); // fail, because A &a = A() doesn't work
auto_ptr и наш класс A используют хитрость, заключающуюся в том, что неконстантные функции-члены могут по-прежнему вызываться для временных / по значению A. То есть мы могли бы также написать:
struct A {
...
B get_b() { return B(*this); }
...
};
...
A a = A().get_b();
Но это работает, мы не хотим беспокоиться об этом, конечно. Мы хотим, чтобы он просто назначал A()
или возвращаемое значение функции, возвращающей значение A
. Так что auto_ptr и наш класс A использует оператор преобразования, который автоматически выясняет, что когда A преобразуется в B, мы можем создать экземпляр A, используя B, который мы создали временно.