2

With C++20 P0052's scope_guards (and many other flavors of scope guards), consider this typical use case:

auto f = std::fopen(/*...*/);
scope_exit guard_f([&](){ std::fclose(f); });

The code relies on that the lambda expression itself (the construction of the closure object) doesn't throw. How does the C++ standard guarantee that?

I read the chapter(§7.5.5 Lambda expressions) of the standard, and found no saying about the noexceptness of lambda constructors.

zwhconst
  • 1,352
  • 9
  • 19
  • There is only stack allocations here when constructing the guard. What do you mean would throw? – super Dec 08 '19 at 10:48
  • 2
    @super, I understand that any reasonable compiler does not throw. I'm just not sure how it's guaranteed by the standard. I'm editing the question now. – zwhconst Dec 08 '19 at 11:39
  • Do you want to know that it for sure never throws OR that the function itself is noexcept and can be processed as such for via type traits – JVApen Dec 08 '19 at 11:55
  • 1
    @JVApen, the former. But you reminded me to test and `int x = 0; static_assert(noexcept([&](){ x = 1; }));` actually compiles in gcc 9.2 (https://godbolt.org/z/aXN6pv). – zwhconst Dec 08 '19 at 12:10
  • It looks like the standard leaves the lambda constructor up to the implementation. If this proposal requires a nothrow lambda constructor to function, and the standard doesn't have an opinion on the signature of lambda constructors in general, is that really a conflict? – parktomatomi Dec 08 '19 at 12:47
  • @parktomatomi I’m sorry for my bad internet connection ... removing that comment right now – L. F. Dec 08 '19 at 14:00

1 Answers1

1

In interpreting the standard, we should assume that the evaluation of an expression doesn't have any observable effects other than what the standard either explicitly specifies (other than in cases where the standard specifies that the behaviour is undefined, unspecified, or implementation-defined).

Surely you would agree that the evaluation of the expression 1 + 1 can never throw. Must there be a sentence in [expr.add] (which governs the built-in addition operator) explicitly stating that an exception is not thrown? Equally, there does not need to be any such sentence in [expr.prim.lambda]. (Though of course the creation of a lambda closure object can throw, if the initialization of any capture throws. This is implied by [expr.prim.lambda.capture]/15, which states that the entities that are captured by copy are direct-initialized, and is explicitly accounted for, e.g. by [except.spec]/6 and [intro.execution]/3.3. All references are to C++20.)

Brian Bi
  • 111,498
  • 10
  • 176
  • 312