Логическое И + назначение в С++, безопасно?
Я только что узнал этот отличный шаблон (из javascript на самом деле), и я хотел бы применить его к моему коду С++.
Чтобы объяснить шаблон, скажем, я представляю строку как связанный список из них:
struct link_char;
struct link_char
{
link_char * next;
char code;
};
Обратите внимание, что последний символ любой строки link_char всегда будет иметь код == 0.
Это свойство означает, что я могу проверить значение в строке, используя && короткое замыкание, чтобы предотвратить доступ к указателю NULL.
bool equals_hello( const link_char * first_char )
{
const link_char * c = first_char;
return c->code=='h'
&& (c=c->next)->code=='e'
&& (c=c->next)->code=='l'
&& (c=c->next)->code=='l' // if string == "hel", we short-circuit here
&& (c=c->next)->code=='o';
}
Мой вопрос касается безопасности, а не читаемости.
Я знаю, что короткое замыкание будет работать до тех пор, пока && не перегружен. Но будут ли операции присваивания выполняться в правильном порядке или определена реализация?
В приведенном выше примере явно указано, где могут выполняться чтения/записи, но я также хотел бы использовать этот шаблон в ситуациях, когда могут быть побочные эффекты. Например:
// think of these as a bunch of HRESULT type functions
// a return value of 0 means SUCCESS
// a return value of non-zero yields an Error Message
int err;
( !(err=initialize()) && !(err=create_window()) && !(err=run_app() )
|| handle_error(err);
Будут ли подобные операции работать как предполагаемые кросс-платформенные? Я читал, что "если вы дважды читаете переменную в выражении, где вы также пишете ее, результат будет undefined". Но интуитивно я чувствую, что короткое замыкание гарантирует порядок, не так ли?
Ответы
Ответ 1
Да.
Встроенный логический И (&&
), логический ИЛИ (||
) и оператор запятой (,
) - это случаи только, в которых для двоичного оператора С++ гарантируется, что оценка будет вычислять левое выражение, а затем (если не коротко замкнутое) правильное выражение (оператор запятой, конечно, всегда оценивает оба операнда, сначала слева, а затем справа).
Заметим также, что запятая между аргументами функции не является оператором запятой, поэтому порядок оценки аргументов функции не указан и даже хуже, чем это: например, в f(g(h()),i())
возможно, что последовательность вызовов будет h,i,g,f
.
Также гарантия на порядок оценки применяется только к встроенным операторам; если вы переопределяете их, то они в основном становятся вызовами функций, где порядок оценки аргументов не гарантируется и где короткое замыкание не выполняется.
Другие двоичные операторы не гарантируют порядок оценки, и, например, одна распространенная ошибка состоит в том, чтобы думать, что в:
std::cout << foo() << bar();
вызов foo()
гарантированно произойдет до вызова bar()
... это не true.
Конечно, порядок оценки также гарантирован для оператора trernary :?
, где только одно из двух других выражений будет оценено после первой оценки условия.
Другим местом, в котором гарантирован порядок оценки (а иногда и неожиданным для новичков), является список инициализации членов для конструкторов, но в этом случае порядок не тот, который указан в выражении, но порядок объявления участника в классе... например:
struct Foo
{
int x, y;
Foo() : y(compute_y()), x(compute_x()) {}
};
в этом случае гарантировано, что вызов compute_x()
будет выполнен ПЕРЕД вызовом compute_y()
, поскольку x
предшествует y
в объявлениях участников.
Ответ 2
Будут ли такие операции работать как предназначенная для кросс-платформенной платформы? я прочел что "если вы дважды читаете переменную выражение, в котором вы также пишете его, результат undefined". интуитивно я чувствую, что короткое замыкание гарантирует заказ, не так ли?
Встроенный оператор &&
имеет гарантированную оценку короткого замыкания, что означает, что он вводит точку последовательности: С++ 98 §5.14/2 "Все побочные эффекты первого выражения, за исключением уничтожения временных рядов (12.2 ) происходит до того, как будет оценено второе выражение.
Так что проблем нет. С++.
Тем не менее, ваше предлагаемое использование, на мой взгляд, очень плохое, поскольку оно неясно. Просто не используйте языковые функции, о которых вы должны спросить, потому что другие, скорее всего, будут так же неясны в отношении них. Кроме того, повторите комментарии в коде, имейте в виду, что Windows HRESULT указывает на сбой при установке бит 31, который сильно отличается от нуля/ненулевого.
Приветствия и hth.,