0

I want to learn all about exceptions in c++ and I found this code here to issue some because my OOM killer on Linux is not issuing terminate. I just don't understand what return d > 1e7 ? throw std::overflow_error("too big") : d; is doing in particular:

#include <iostream>
#include <stdexcept>

double f(double d)
{
    return d > 1e7 ? throw std::overflow_error("too big") : d; //what is going on here?
}
int main()
{
    try {
        std::cout << f(1e10) << '\n';
    } catch (const std::overflow_error& e) {
        std::cout << e.what() << '\n'; // information from length_error printed
    }
    return 0;
}
Ingo Mi
  • 999
  • 12
  • 26
  • 5
    Sounds like you could use a [good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – NathanOliver Feb 25 '20 at 20:10
  • 2
    What is there not to understand? There is a call to the `f()` function inside a `try` block, and that function throws a `std::overflow_error` exception if the `d` parameter is not valid, which the `catch` block then catches. You are going to have to be more specific about what exactly you do not understand about that. – Remy Lebeau Feb 25 '20 at 20:11
  • 1
    you asked a very similar [question](https://stackoverflow.com/questions/60401204/how-to-issue-a-c-termination-catch-without-a-oom-killer). Imho you should mention this and explain how this one is different. Why does the answer you got there does not apply here? I have the same comment here again: Why do you expect the program to terminate when you catch the exception? – 463035818_is_not_an_ai Feb 25 '20 at 20:12
  • "how is this piece of code working" is a REALLY generally broad question. What specifically would you like to know? – Wyck Feb 25 '20 at 20:14
  • 1
    Possible search term: Ternary Operator. – user4581301 Feb 25 '20 at 20:15
  • The `? :` thing is basically a shorthand for `if (d > 1e7) throw ...; else return d;`. – HolyBlackCat Feb 25 '20 at 20:17
  • 1
    Is it the `xxx ? yyy : zzz` expression that's confusing you? That's called the [Conditional (or Ternary) Operator](http://www.cplusplus.com/articles/1AUq5Di1/). – Wyck Feb 25 '20 at 20:19
  • @idclev463035818 In that question I asked how to throw an exception if the os is not issuing and now I want to know what the code in a programmed "thrown" exception is doing. Makes sense? – Ingo Mi Feb 25 '20 at 20:35
  • 1
    I have no idea how you think the OOM killer relates to your code. Please explain your thought process. Otherwise there is no way to help you. – walnut Feb 25 '20 at 20:36
  • @Wyck Thanks, i guess that helps. And what would be 1e7 since it is not defined as variable anywhere, isn't it? Or is that ASM? – Ingo Mi Feb 25 '20 at 20:37
  • 1
    kind of makes sense, but same as walnut, I dont understand why the OOM killer is relevant here or why you (again) expect this to terminate. If your question is about that particular line `return d > 1e7 ? throw std::overflow_error("too big") : d;` you could make this more clear in the question. Comments in code are easily overlooked, I tend to ignore them completely – 463035818_is_not_an_ai Feb 25 '20 at 20:37
  • @idclev463035818 Ah ok, I edit the question, thanks for that hint – Ingo Mi Feb 25 '20 at 20:39
  • 2
    @user4581301 `1e7` is another way of writing `10000000.0`. You really need to learn C++ in a structured way from a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). If you see something new that you don't know, first make an effort to search for previous questions on it and if you don't find anything, ask specifically about that one thing, e.g. "What does `1e7` in this code mean?". For example when I google for `c++ 1e7` the second link I get is [this question](https://stackoverflow.com/questions/26174531/what-is-the-meaning-of-number-1e5). – walnut Feb 25 '20 at 20:42
  • @walnut What book did you use to learn in a structured way? I already spent about 2000USD for c++ programming books - I think I got all of that list. Most of them are like trying to read school books and written for ?? and producing more questions than answers like the strousrup one ore the primer. But I worked through jump to c++ and that actually made fun. Are Ternary conditions used that often? – Ingo Mi Feb 25 '20 at 20:49
  • @walnut thanks for the edit - the whole line was confusing me, thought it was some special kind of asm code snipped or something, maybe to much debugging code today - I will search for the single words in the future, thanks for that tip and being helpful – Ingo Mi Feb 25 '20 at 20:55
  • the `e` in the numeric literal reads like `times 10 to the power of` – Wyck Feb 25 '20 at 21:00
  • I still do not understand why you expect [`std::terminate`](https://en.cppreference.com/w/cpp/error/terminate) to be called. It gets called in certain situations, as enumerated. You can call it yourself, too, in your `catch` block. – Eljay Feb 25 '20 at 21:00
  • @Eljay I am reading through a structured book that claims a certain code throws a termination but since my os has no OOM killer i need to simulate kind of a "windows like" behavior for being able to follow the examples and the book. – Ingo Mi Feb 25 '20 at 21:07
  • 1
    @Ivanovic `std::terminate` is called when you don't catch an exception that was thrown anywhere. One such exception is `std::bad_alloc` which is thrown when you try to allocate memory but there isn't any memory left (or the allocation fails for another reason). If you don't catch that exception when you run out-of-memory then `std::terminate` will be called and it will end the program. This has nothing to do with the OS or the OOM killer. Depending on how your system is set up, it will however always pretend that there is still space left and so `std::bad_alloc` will never be thrown. – walnut Feb 25 '20 at 21:12
  • 1
    If that is the case, then the program will just crash or be killed by the OS when it tries to actually read/write from/to too much of the memory it allocated. `std::terminate` is always called *by the program itself*. – walnut Feb 25 '20 at 21:13
  • @walnut Yeah, it seem to pretend in my case and the system just freeze and doesn't throw anything at all if the swap is off. Same with the swap on with a few GB allocated. So understand I right that "std::terminate is always called by the program itself." means std::terminate is always running and I don't have to code it and i can just customize the catch message as kind of "feature" or just leave it default? – Ingo Mi Feb 25 '20 at 21:51
  • For OOM, try `char* p = new char[~0ULL];` ... that should do the trick. – Eljay Feb 25 '20 at 22:22
  • @Eljay doesn't even compile error: array is too large (18446744073709551615 elements) but looks interesting. How does ~0ULL stand for that number f.e. 18446744073709551615? – Ingo Mi Feb 25 '20 at 22:38
  • 1
    `~0ULL` is the bitwise complement of unsigned long long 0. – Eljay Feb 25 '20 at 23:40

1 Answers1

3

OK, let's look at it step by step:

I imagine your confusion is from one of two places:

d > 1e7

or, the syntax of:

a ? b : c;

So for starters, 1e7 is a form of scientific notation, basically 1 times 10 to the 7th power, or in other words 10000000

So d > 1e7 is basically the same as writing: d > 10000000.0

The next bit is called the conditional operator, or "ternary operator". it comes in the form of a ? b : c. Basically what it means is "if a is true, then the result of the expression is b, otherwise, the result of the expression is c.

So in summary, we can rewrite your return statement like this:

if(d > 10000000.0) {
    throw std::overflow_error("too big");
} else {
    return d;
}

NOTE Typically, both the b and c of a ternary operator expression have to be convertible to a mutual type, but throwing an exception is one of the... exceptions to that rule since it diverts control flow to the handler, and thus returns nothing at all.

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • Thanks, that was really helpful! ternary operators makes the code really lean. – Ingo Mi Feb 25 '20 at 21:05
  • 1
    @Ivanovic No problem. Also, I saw your other question about the OOM killer. Just so you know, Linux, by design new will essentially **never** throw `std::bad_alloc` because it uses an allocation strategy called "over-provisioning". What this means is that allocations are always "approved" even if there isn't enough RAM. When you try to actually touch RAM that it can't provide (due to there not being enough), **then**, it will cause an error. – Evan Teran Feb 25 '20 at 21:08
  • Thanks for that hint. Just the system freeze before it gets in the "over-provisioning" range if I turn off the swap like f.e. with # swapoff -a. I guess an overflow_error is not the same as a std::bad_alloc error - but at least I can execute catch statements. – Ingo Mi Feb 25 '20 at 21:14
  • 1
    @EvanTeran Well, depends on the overcommit setting. And process limits. – Deduplicator Feb 25 '20 at 21:18
  • 1
    @Deduplicator Sure, that's fair enough. Though I've admittedly never seen Linux actually fail to allocate memory personally. – Evan Teran Feb 25 '20 at 21:22
  • @EvanTeran I use linux for several years now and it is the first time the system freeze and its just provoked by allocating the memory infinite – Ingo Mi Feb 25 '20 at 22:07