Другие ответы касаются того, как это работает, но я думаю, вам нужно сказать, почему он был добавлен в C ++.
Умный указатель обычно имеет преобразование в bool
, поэтому вы можете сделать это:
std::shared_ptr<int> foo;
if (foo) {
*foo = 7;
}
, где if(foo)
преобразует foo
в bool
.К сожалению:
int x = foo+2;
преобразует foo
в bool
, затем в int
, затем добавляет 2
.Это почти всегда ошибка.Это разрешено, потому что, хотя выполняется только одно пользовательское преобразование, пользовательское преобразование, за которым следует встроенное преобразование, может произойти в молчании.
Чтобы исправить это, программисты должны делать сумасшедшие вещи, такие как add:
struct secret {
void unused();
};
struct smart_ptr {
using secret_mem_ptr = void(secret::*)();
operator secret_mem_ptr() const { return 0; }
};
и secret_mem_ptr
- это секретный указатель на член.Указатель на член имеет встроенное преобразование в bool
, поэтому:
smart_ptr ptr;
if (!ptr) {
}
"работает" - ptr
преобразуется в secret_mem_ptr
, который затем преобразуется в bool
, чтозатем используется, чтобы решить, какую ветвь взять.
Это было больше чем хак.
Они добавили explicit
в операторы преобразования для решения этой конкретной проблемы.
Сейчас:
struct smart_ptr {
explicit operator bool() const { return true; }
};
не разрешает:
smart_ptr ptr;
int x = 3 + ptr;
, но разрешает:
if (ptr) {
}
, потому что правила были созданы вручную для поддержкиименно этот вариант использования.Это также не разрешает:
bool test() {
smart_ptr ptr;
return ptr;
}
здесь, вы должны ввести:
bool test() {
smart_ptr ptr;
return (bool)ptr;
}
, где вы явно конвертируете ptr
в bool
.
(Я обычно действительно против бросков в стиле C; я делаю исключение в случае (bool)
).