5

How does noexcept in C++ change the assembly? I tried a bit with small functions, in godbolt, but the assembly did not change.

float pi() 
//noexcept // no difference
{ return 3.14; }

int main(){
    float b{0};
    b = pi();
    return 0;
}

I am looking for a minimal working example, where I can see a change in the assembly due to noexcept.

Jonas Stein
  • 6,826
  • 7
  • 40
  • 72
  • 4
    In certain cases, it can be a massive change, such as with `std::vector` where if `MyType`'s move constructor is not `noexcept`, `std::vector` has to copy the elements when it resizes, rather than just move them. In other cases, as you've seen, it can make no difference. In short, `noexcept` doesn't "change the assembly", but it provides semantic meaning that library code can rely on, which can eventually cause significant changes in the assembly, or no changes in the assembly. – Justin Jun 26 '19 at 23:45
  • 5
    The body of a `noexcept` function may also be compiled in a much more optimized way, since local variables won't need to be destroyed correctly in the case of an exception. See here: https://stackoverflow.com/questions/26079903/noexcept-stack-unwinding-and-performance – alter_igel Jun 26 '19 at 23:51
  • Your example is too simple, the compiler knew already it is noexcept, without you telling it. Use a more complex example, for example calling a further function that is in another code file, so the compiler cannot see it is for sure noexcept. – Aganju Jun 27 '19 at 02:08
  • 1
    Of course the `noexcept` statement might also result in a different assembly code for the **calling** function (especially if that function contains a `try`-`catch` statement). – Martin Rosenau Jun 27 '19 at 04:36
  • 1
    `noexcept` really only makes a difference when A) there are destructors to run so there are non-trivial items to destruct B) exceptions *could* be thrown and thus the compiler would have to handle those cases. – Mgetz Jun 27 '19 at 14:16

1 Answers1

3

Pretty simple examples can be constructed that involve destructors directly rather than introspection on noexcept status:

void a(int);
void b() noexcept;
void c(int i) {
  struct A {
    int i;
    ~A() {a(i);}
  } a={i};
  b();
  a.i=1;
}

Here, the noexcept allows the initialization of a in the caller to be ignored, since the destructor cannot observe it.

struct B {~B();};
void f();
void g() noexcept {
  B b1;
  f();
  B b2;
}

Here, the noexcept allows the omission of frame information needed in case the callee throws. This depends on the (very common) decision to not unwind the stack when calling std::terminate.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76