Хорошая ли идея перегружать оператор && в C++?

Ответ

Перегрузка оператора && в C++ технически возможна, но на практике это считается плохой идеей, так как она нарушает ожидаемую семантику короткого замыкания (short-circuit evaluation).

Проблема: Встроенный оператор && вычисляет правый операнд только если левый операнд равен true. Перегруженный оператор — это обычный вызов функции, поэтому оба аргумента вычисляются полностью до входа в тело функции.

Пример, демонстрирующий разницу:

bool returnsFalse() {
    std::cout << "Side effect: returnsFalse calledn";
    return false;
}
bool returnsTrue() {
    std::cout << "Side effect: returnsTrue calledn";
    return true;
}

// Встроенный оператор
if (returnsFalse() && returnsTrue()) {}
// Вывод: "Side effect: returnsFalse called"
// Функция returnsTrue() НЕ вызывается.

// Перегруженный оператор (если бы он существовал для какого-то типа)
// MyClass a, b;
// if (a && b) { ... }
// Обе функции-преобразования для a и b будут вызваны ПЕРЕД вычислением оператора.

Это может привести к неочевидным ошибкам, если правый операнд имеет побочные эффекты (вызов функции, изменение состояния, выделение памяти). Поэтому перегрузку &&||, и ,) следует избегать, чтобы не вводить в заблуждение пользователей вашего кода. Для подобной логики лучше использовать именованные методы.

Ответ 18+ 🔞

Давай разберем эту хитрую тему, а то тут, бля, подвох есть, как в дешёвом паленом коньяке.

Смотри, технически-то перегрузить оператор && в C++ можно, ёпта. Компилятор даже не ругнётся. Но делать это — это всё равно что на спортивный Ferrari поставить гужевую сбрую. Выглядит как будто бы прикольно, а на деле — пиздопроебибна идея, которая всё сломает.

В чём, собственно, подпиздятина? А в том, что родной, встроенный оператор && — хитрая жопа. Он умный. Он сначала левую часть посмотрит. Если она false, то он даже правую часть вычислять не станет, забивает болт. Это называется «короткое замыкание». А перегруженный оператор — это по сути обычная функция, чувак. А в функцию-то аргументы передаются ВСЕГДА, и они ВСЕГДА вычисляются до того, как ты в эту функцию зайдешь. Понимаешь разницу? Доверия ебать ноль к такому поведению.

Смотри на примере, тут всё станет ясно как божий день.

bool returnsFalse() {
    std::cout << "Side effect: returnsFalse calledn";
    return false;
}
bool returnsTrue() {
    std::cout << "Side effect: returnsTrue calledn";
    return true;
}

// Родной оператор, честный пацан
if (returnsFalse() && returnsTrue()) {}
// Вывод: "Side effect: returnsFalse called"
// returnsTrue() даже не пискнула! Её и не позвали, потому что левая часть уже false.

// А теперь представим, что у нас есть свой класс, и мы нагородили свой `operator&&`
// MyClass a, b;
// if (a && b) { ... }
// А вот тут уже будет пиздец. Сначала компилятор дохуя сметливый вычислит ВСЕ преобразования для 'a' и ВСЕ преобразования для 'b',
// и только потом засунет результаты в нашу перегруженную функцию. Побочные эффекты — на все деньги!

Представь, если в правой части у тебя не просто true, а, например, файл открывается или память выделяется, или ещё какая ядрёна вошь происходит. При родном операторе, если левая часть провалилась, этого всего не случится. А при твоём самопальном — случится обязательно, и потом будешь сидеть и чесать репу: «И чё это у меня пол-оперативки сожралось, хотя условие в if не выполнилось?».

Поэтому все адекватные дядьки в один голос орут: не еби мозги, не перегружай &&, || и запятую. Это операторы с особыми правами, их семантика святая. Хочешь сложную логику — напиши нормальный именованный метод, типа isValidAndReady() или что-то такое. Вы ходите по охуенно тонкому льду, когда лезете в эту тему.

Короче, вывод простой: можно, но не нужно. Это тот самый случай, когда возможность есть, а толку от неё — хуй с горы. Только себе и другим жизнь усложнишь.