Problem
The delete this
in your code is called in both cases regardless of the optimization options.
if (m_selfDestructTrigger) {
delete this;
}
In your code, the "b" object gets deleted, but then you "evaluate()" it, and it causes the Access Violation, because you are using heap that was already freed.
It gives the Access Violation error in both Release and Debug configurations in my case, but in your case the Access Violation may not happen with optimizations for the following reason.
There may be cases such as in your one, when using freed heap does not cause the error and you have the impression that the program works fine (as with optimizations or in the Release configuration), because the freed heap is not cleared and keeps the old object.
It is not the compiler error but the way how you delete objects.
It is generally a bad style for the objects to delete themselves because you may then reference a deleted object, as was in your case. There is a discussion on whether objects should delete themselves.
If you comment the "delete" line, you code will run without Access Violation. You can use a simpler method to debug an application if you still suspect it might have been a compiler error and "the execution jumps straight to the lambda". This simpler method is to avoid the "delete" and output some text instead from the blocks of code that you suspect are skipped by the compiler.
Solution
You can use another compiler, particularly, clang with sanitizers to make sure that it is not a error of the Microsoft Visual Studio compiler that you are using.
For example, use:
clang++.exe -std=c++20 -fsanitize=address calc.cpp
and run the resulting executable file.
In this example, your code is compiled with "Address Sanitizer", which is a memory error detector supported by this compiler. Using various sanitizers may help you in debugging your C/C++ programs in future.
You will get an error like this that shows that you are using heap after freeing it:
=================================================================
==48820==ERROR: AddressSanitizer: heap-use-after-free on address 0x119409fa0380 at pc 0x7ff799c91d6c bp 0x004251cff720 sp 0x004251cff768
READ of size 1 at 0x119409fa0380 thread T0
#0 0x7ff799c91d6b in main+0xd6b (c:calcclangcalc.exe+0x140001d6b)
#1 0x7ff799c917de in main+0x7de (c:calcclangcalc.exe+0x1400017de)
#2 0x7ff799cf799f in __scrt_common_main_seh d:agent\_work63ssrcvctoolscrtvcstartupsrcstartupexe_common.inl:288
#3 0x7ffe3cff53fd in BaseThreadInitThunk+0x1d (C:WINDOWSSystem32KERNEL32.DLL+0x1800153fd)
#4 0x7ffe3ddc590a in RtlUserThreadStart+0x2a (C:WINDOWSSYSTEM32
tdll.dll+0x18006590a)
0x119409fa0380 is located 16 bytes inside of 24-byte region [0x119409fa0370,0x119409fa0388)
freed by thread T0 here:
#0 0x7ff799cf6684 in operator delete C:srcllvm_package_6923b0a7llvm-projectcompiler-rtlibasanasan_new_delete.cpp:160
#1 0x7ff799c91ede in main+0xede (c:calcclangcalc.exe+0x140001ede)
#2 0x7ff799c916e4 in main+0x6e4 (c:calcclangcalc.exe+0x1400016e4)
#3 0x7ff799cf799f in __scrt_common_main_seh d:agent\_work63ssrcvctoolscrtvcstartupsrcstartupexe_common.inl:288
#4 0x7ffe3cff53fd in BaseThreadInitThunk+0x1d (C:WINDOWSSystem32KERNEL32.DLL+0x1800153fd)
#5 0x7ffe3ddc590a in RtlUserThreadStart+0x2a (C:WINDOWSSYSTEM32
tdll.dll+0x18006590a)
Proof
You can also use the following batch file to compare the output of the two version compiled with and without optimization by clang to find out that they produce the same results:
clang++ -std=c++20 -O3 -o calc-O3.exe calc.cpp
clang++ -std=c++20 -O0 -o calc-O0.exe calc.cpp
calc-O3.exe > calc-O3.txt
calc-O0.exe > calc-O0.txt
fc calc-O3.txt calc-O0.txt
It will give the following:
Comparing files calc-O3.txt and calc-O0.txt
FC: no differences encountered
For the Microsoft Visual Studio compiler, use the following batch file:
cl.exe /std:c++latest /O2 /Fe:calc-O3.exe calc.cpp
cl.exe /std:c++latest /Od /Fe:calc-O0.exe calc.cpp
calc-O3.exe > calc-O3.txt
calc-O0.exe > calc-O0.txt
fc calc-O3.txt calc-O0.txt
It also produce identical results, so the code runs the same way regardless of optimization (rather than "all of the code in evaluate gets skipped entirely" as you wrote) - you have probably debugged it incorrectly due to optimizations.