逻辑与 + c++ 中的赋值安全吗?

发布于 2024-11-18 06:41:02 字数 1203 浏览 4 评论 0原文

我刚刚学到了这个很棒的模式(实际上是从 javascript 学到的),我想将它应用到我的 C++ 代码中。

为了解释该模式,假设我将一个字符串表示为这些字符串的链接列表:

struct link_char;
struct link_char
{
   link_char * next;
   char code;
};

请注意,任何 link_char 字符串的最后一个字符始终为 code==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);

这些类型的操作能否按预期跨平台运行?我读过“如果您在表达式中读取一个变量两次并同时写入它,则结果是未定义的”。但直觉上我觉得短路保证了顺序,不是吗?

I just learned this great pattern (from javascript actually) and I would like to apply it to my c++ code.

To explain the pattern, let's say I am representing a string as a linked list of these:

struct link_char;
struct link_char
{
   link_char * next;
   char code;
};

Note that the last character of any link_char string will always have code==0.
This property means that I can check for a value in the string, while using && short-circuiting to prevent NULL pointer access.

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';
}

My question is about safety, not readability.
I know the short-circuiting will work as long as && is not overloaded. But will the assignment operations happen in the right order, or is it implementation defined?

The above example is explicit about where reads/writes can happen, but I would also like to use this pattern in situations where there can be side-effects. For example:

// 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);

Will these kinds of operations work as intended cross-platform? I've read that "if you read a variable twice in an expression where you also write it, the result is undefined". But intuitively I feel like the short-circuiting guarantees the order, does it not?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

中性美 2024-11-25 06:41:02

是的。

内置逻辑 AND (&&)、逻辑 OR (||) 和逗号运算符 (,) 是 对于二元运算符,C++ 保证求值将计算左表达式,然后(如果不是短路)右表达式(逗号运算符当然总是计算两个操作数,先左后右)。

另请注意,函数参数之间的逗号不是逗号运算符,因此未指定函数参数的求值顺序,甚至更糟:例如在 f(g(h()),i()) 中 调用顺序可能是 h,i,g,f

另外,关于评估顺序的保证仅适用于内置运算符;如果您重新定义它们,那么它们基本上会变成函数调用,其中参数的求值顺序无法保证并且不执行短路。


Other binary operators don't guarantee the order of evaluation and for example one common mistake is to think that in:

std::cout << foo() << bar();

foo() 的调用保证在对 bar() 的调用之前发生...这是正确的。

(C++17 修复了这个问题,但仅限于少数非常特殊的情况,包括左移运算符,因为它用于流)

当然,三元的求值顺序也得到了保证> :? 运算符,在第一次计算条件后,仅计算其他两个表达式之一。

保证求值顺序的另一个地方(有时会让新手感到惊讶)是构造函数的成员初始化列表,但在这种情况下,顺序不是表达式中的顺序,而是成员的顺序在类中声明......例如:

struct Foo
{
   int x, y;
   Foo() : y(compute_y()), x(compute_x()) {}
};

在这种情况下,保证调用compute_x()将在调用compute_y()<之前完成/代码> 因为在成员声明中,x 位于 y 之前。

Yes.

Built-in logical AND (&&), logical OR (||) and the comma operator (,) are the only cases in which for a binary operator C++ guarantees that evaluation will compute left expression and then (if not short circuited) right expression (comma operator of course always evaluates both operands, first left and then right).

Note also that the comma between function arguments is not a comma operator and therefore the order of evaluation of function arguments is not specified and even worse than that: for example in f(g(h()),i()) it is possible that the sequence of calls will be h,i,g,f.

Also the guarantee about evaluation order only applies to built-in operators; if you redefine them then they basically become function calls where the order of evaluation of arguments is not guaranteed and where short-circuiting is not performed.


Other binary operators don't guarantee the order of evaluation and for example one common mistake is to think that in:

std::cout << foo() << bar();

the call to foo() is guaranteed to happen before the call to bar() ... this is not true.

(C++17 fixed this issue but only in a few very special cases, including the left shift operator because it's used for streams)

Of course the order of evaluation is also guaranteed for the ternary :? operator, where only one of the two other expressions will be evaluated after first evaluating the condition.

Another place in which the order of evaluation is guaranteed (and sometimes surprising for newbies) is member initialization lists for constructors, but in this case the order is not the one in the expression, but the order of member declaration in the class.... for example:

struct Foo
{
   int x, y;
   Foo() : y(compute_y()), x(compute_x()) {}
};

in this case it is guaranteed that the call compute_x() will be done BEFORE the call compute_y() because x precedes y in the member declarations.

薄情伤 2024-11-25 06:41:02

这些类型的操作会像
打算跨平台吗?我读过
“如果你读取一个变量两次
一个你也可以写它的表达式,
结果是未定义的”。但是
直觉上我觉得
短路保证顺序,
不是吗?

内置的 && 运算符保证了短路求值,这意味着它引入了一个序列点: C++98 §5.14/2 “第一个表达式的所有副作用,除了临时变量(12.2)的破坏发生在评估第二个表达式之前”。

所以没有问题。 C++。

在我看来,您建议的用法仍然非常不好,因为它很晦涩。只是不要使用您必须询问的语言功能,因为其他人很可能同样不清楚它们。另外,请重新注释代码,请注意,当设置第 31 位时,Windows HRESULT 表示失败,这与零/非零有很大不同。

干杯&呵呵,

Will these kinds of operations work as
intended cross-platform? I've read
that "if you read a variable twice in
an expression where you also write it,
the result is undefined". But
intuitively I feel like the
short-circuiting guarantees the order,
does it not?

The built-in && operator has guaranteed short-circuit evaluation, which means that it introduces a sequence point: C++98 §5.14/2 "All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated".

So there's no problem wrt. C++.

Still your suggested usage is in my opinion very ungood, since it is obscure. Simply don't use language features that you have to ask about, because others will most probably be similarly unclear about them. Also, re comments in the code, be aware that a Windows HRESULT indicates failure when bit 31 is set, which is very different from zero/non-zero.

Cheers & hth.,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文