-fno-exceptions doesn't get rid of exceptions, it just causes your program to abort when one is thrown, which sounds--kind of worse? How do you deal with (for example) a constructor that fails? And if you're using the Standard Library, it is very difficult to avoid code that might throw an exception.
> How do you deal with (for example) a constructor that fails?
The usual alternative is to have a factory function that returns std::optional<T> or std::expected<T, Err>. This avoids two-stage init, but has other tradeoffs.
Works rather well in rust but in c++ its not as nice for one because of the lack of something like rusts question mark operator. (Tbf thats kinda workaroundable with compiler extensions but MSVC for example doesn‘t have most of them)
In other words, you introduce an invalid state to every object and make constructing objects a lot more cumbersome. The first is the exact opposite of the (imo highly desirable) "make invalid states unrepresentable" principle, and the second is also a pretty extreme cost to productivity. I wouldn't say this is never worth it, but it's a very high price to pay.
A better solution than what rmholt said is to have a static method that returns std::optional<T>. This way if T exists, it's valid.
Later you get into another whole debate about movable types and what T should be once it's moved from (for example if you want to turn that std::optional<T> into a std::shared_ptr<T>), if it only has non-trivial constructors. An idea that just popped into my head would be to have a T constructor from std:optional<T>&&, which moves from it and resets the optional. But then it's not a real move constructor. With move constructors, a lot of times you just have to accept they'll have to leave the other object in some sort of empty or invalid state.
I'm not saying it's perfect but it's better than dealing with C++ exceptions. At least with error codes you can manually do some printing to find out what went wrong. With C++ exceptions you don't even get a line number or a stack trace.
You do get invalid states with exceptions in much worse way. Think exception thrown from a constructor, or, even better, from a constructor of one of the members even before the constructor's body is reached. Not to mention managing state becomes much more complicated when every statement can cause stack unwinding unexpectedly.