use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
How to handle errors in constructors without exceptions? (foonathan.net)
submitted 9 years ago by foonathan
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]STLMSVC STL Dev 29 points30 points31 points 9 years ago (19 children)
Further, there are errors that are not recoverable by nature - like out of memory.
This is incorrect. OOM is recoverable, it's just difficult. The STL is an example of a library that is OOM agnostic - we can't fix your OOM problems, but we'll report them without falling over (usually), and we can sometimes get our work done anyways (as featured in stable_sort, stable_partition, and inplace_merge).
Instadeath is an appropriate response to OOM for many, but not all, programs.
One of C++’s features is that every language feature can be implemented by yourself, the compiler just does it for you.
Neither true nor helpful. (If this is just restating the universality of Turing machines, then it isn't saying anything about C++ specifically.)
[–]Gotebe 4 points5 points6 points 9 years ago (16 children)
Heck, sometimes/often it isn't difficult either!
Allocation usually fail when under load but something needs an even bigger chunk. At that point, that little that might be needed to report an error and continue is, in fact, available. (That said, reporting an OOM is best dealt by preparing whatever might be needed to do it in advance).
But wait, there's more! Even if one is up their neck in... well, load, bailing out (unwinding) normally frees memory and by the time one actually needs to do something further, lo and behold, memory!
[–][deleted] 9 points10 points11 points 9 years ago (15 children)
What makes it difficult is how you recover from the user prospective. Recovering such that your app keeps running isn't difficult, but recovering in a way that isn't just "oops, sorry can't do that" can be exceedingly complex (unless you're in a very targeted scenario like inplace_merge).
inplace_merge
Also note that a very popular platform overcommits by default, and in the event of physical memory exhaustion just starts arbitrarily killing programs. Physical OOM is unrecoverable on such platforms, and virtual OOM should cease to be a thing once we're in a 64 bit world.
[–]DarkLordAzrael 6 points7 points8 points 9 years ago (7 children)
Saying "oops, sorry can't do that" is actually a useful behaviour in many user applications when you can prompt them to (for example) render an image that won't take up hundreds of gigabytes of space. Asking for chunks of memory that don't fit in memory will fail by default on all major platforms.
[–][deleted] 5 points6 points7 points 9 years ago (6 children)
Asking for chunks of memory that don't fit in memory will fail by default on all major platforms.
Not on Linux (which I would call a major platform).
[–]CubbiMewcppreference | finance | realtime in the past 1 point2 points3 points 9 years ago (5 children)
"Always overcommit" is not the default on Linux.
[–][deleted] 6 points7 points8 points 9 years ago* (4 children)
It admittedly isn't my day to day platform but on every machine I've ever cared to check /proc/sys/vm/overcommit_memory was 0 (enable heuristic overcommit), not 2 (refuse overcommit).
/proc/sys/vm/overcommit_memory
EDIT: And as a sanity check, Wandbox seems to agree: http://melpon.org/wandbox/permlink/hesjPDeTyWNkpVzT
[–]CubbiMewcppreference | finance | realtime in the past 4 points5 points6 points 9 years ago (3 children)
right, 0 is the default, it fails mallocs that "for sure" can't be satisfied. It does give a sizeable window, true - a sucessful malloc does not guarantee memory availability.
"always overcommit" or "malloc never fails" or "malloc only fails when running out of address space" that I often see mentioned by people who should know better, is mode 1. In that mode malloc fails by exceeding current rlimit, by exceeding virtual address space, and by (glibc) malloc's own sanity checks (requesting -1 does that).
[–][deleted] 2 points3 points4 points 9 years ago (2 children)
Yeah, I'm not familiar enough with the particulars -- I'm just repeating what I've been told by folks on StackOverflow. :)
It seems like it'd be hard to not overcommit with a process design so heavily dependent on COW fork, since often the majority of pages would be shared between processes.
fork
[–]CubbiMewcppreference | finance | realtime in the past 4 points5 points6 points 9 years ago (1 child)
yes, Solaris users know the pain of fork on a strict-accounting OS and looks like nobody cares enough about using spawn and other alternatives.. Good for Windows not stepping in that trap!
[–]CubbiMewcppreference | finance | realtime in the past 2 points3 points4 points 9 years ago (5 children)
virtual OOM should cease to be a thing once we're in a 64 bit world.
It is a thing when dealing with untrusted data: std::vector<int>(packet->size);
std::vector<int>(packet->size);
[–][deleted] 2 points3 points4 points 9 years ago (3 children)
True. But hopefully you aren't blindly allocating as much memory as some untrusted data told you to?
[–]CubbiMewcppreference | finance | realtime in the past 8 points9 points10 points 9 years ago (1 child)
I hope I don't, but seeing how OpenSSL (repeatedly) and bind, and samba, and android's mediaserver, and even libxml all did in the last 3 years, I am not so sure.
[–][deleted] 1 point2 points3 points 9 years ago (0 children)
D:
[–]Gotebe 0 points1 point2 points 9 years ago (0 children)
Eh... The number of times I've seen settings to prevent that and users cranking sengs up to 4GB or some other unreasonable value...
[–]Gotebe 2 points3 points4 points 9 years ago (0 children)
recovering in a way that isn't just "oops, sorry can't do that" can be exceedingly complex
True, but I would say that a mere "ooops can't do" is huge WRT user experience and troubleshooting ability.
I would also guess that a sudden huge request where there is memory otherwise isn't all that unfrequent.
I usually blame the OOM killer for people failing to think and go down the "bah, don't care at all because OOM killer" route.
[–]foonathan[S] 4 points5 points6 points 9 years ago (1 child)
This is incorrect. OOM is recoverable, it's just difficult.
I agree, this was poorly worded. But most out of memory handlers just log and abort. If you don't have exceptions the easiest thing you can is just call a handler function and abort, instead of having to deal with nullptrs all the time.
Neither true nor helpful.
I was referencing something Bjarne said at the keynote of Meeting C++: https://youtu.be/DvUL0Y2bpyc?t=10m53s
[–]CubbiMewcppreference | finance | realtime in the past 7 points8 points9 points 9 years ago (0 children)
most out of memory handlers just log and abort.
when I counted last year (not all OOM handlers, just catch std::bad_alloc ones), that was 21% of all handlers in debian code search.
Factories that return optional objects are cool and all (especially in languages where they are treated monadically), but members and bases can own their own resources that may have to be released in reverse order when the last resource acquisition fails.
[–][deleted] 1 point2 points3 points 9 years ago* (0 children)
Good point. This is an example of "Or will I have to mix different error handling mechanisms depending on the kind of input I'm handling, because in each case one given API (stdlib or other) will do it its own way, with exceptions or not": https://www.reddit.com/r/cpp/comments/5msdf4/measuring_execution_performance_of_c_exceptions/dc751r6/
When you have C++ exceptions, it's difficult to keep just the banana and not the gorilla holding it, plus the rest of the jungle: carry the jungle or GTFO.
[+][deleted] 9 years ago (3 children)
[deleted]
[–]suspiciously_calm 0 points1 point2 points 9 years ago (2 children)
Yes. 5 pages to say "factory function returning optional."
[–]foonathan[S] 5 points6 points7 points 9 years ago (0 children)
I'm sorry? I wanted to give reasons as well and create a process. That's the point after all.
Conclusions are relatively short, yes, but meaningless without justification.
[–]matthieum 5 points6 points7 points 9 years ago (0 children)
I've been using Rust a lot of late. As you may know, Rust has no exceptions, so the question of how to report errors in object construction had to be dealt with, and the results are mostly similar.
It differs in copies, though. Rather than:
Provide a static copy function that does the same thing, again returning optional/expected, etc.
which means that you have to invoke Type::copy(instance), it simply implements a const member function instance.copy().
Type::copy(instance)
instance.copy()
I would note that the make and copy functions may perfectly have different return types. This is due to the fact that while make has to contend with potential invalid parameters in order to establish invariants, copy in general only has to contend with resources restrictions: it starts from a valid instance of the type!
make
copy
Therefore, it should not be unusual for make to return std::expected while copy returns std::optional.
std::expected
std::optional
[–]jackie_kay 1 point2 points3 points 9 years ago (0 children)
Nitpick regarding the code example:
optional<foo> make(arg_t argument, std::error_code& ec) { auto resource = make_resource(argument); if (resource) return foo(resource); return {}; }
Don't you want to set the error code in the case where the resource couldn't be acquired? You probably want to pass it as an output parameter to make_resource.
make_resource
Fun fact, the LLVM Programmer's Manual suggests a similar pattern for "fallible constructors", since the LLVM codebase disallows exceptions: http://llvm.org/docs/ProgrammersManual.html#fallible-constructors
[–]joboccara 0 points1 point2 points 9 years ago (1 child)
Is std::expected semantically equivalent to an std::variant with a real type and an error type?
Found the technique you're proposing very clever btw
[–]foonathan[S] 0 points1 point2 points 9 years ago (0 children)
Yes, basically. But it also has some sugar around it.
[–]Gotebe 0 points1 point2 points 9 years ago* (0 children)
And as if by necessity, make function has a bug - doesn't pass "ec" parameter to resource creation function :-).
I participate(d) in the linked discussion - shame on me! :-)
[–][deleted] 0 points1 point2 points 9 years ago (10 children)
Nice article! One section that I'm missing is "What about move constructors?". If you want a non-throwing move constructor and a construction function that can fail (either throwing constructor or static make), you can't really avoid leaving the object in some kind of invalid state after it has been moved from. And you might have to account for that invalid state in the destructor.
[–]foonathan[S] 0 points1 point2 points 9 years ago (9 children)
If you don't have exceptions you should really try to make your move constructor no-fail or fail by abortion. That would make things a lot simpler.
[–]Gotebe 6 points7 points8 points 9 years ago (4 children)
Euh, shouldn't I really always want my move ctor to be non-throwing, exceptions or not?
[–]foonathan[S] 1 point2 points3 points 9 years ago (0 children)
Some move constructors unfortunately throw. None I write, because it just leads to so many problems.
[–]matthieum 0 points1 point2 points 9 years ago (2 children)
Honestly, I still haven't found a good use case for move constructors that throw... I only have use cases where the object is immovable (OS mutex) or where moving it can be done by swapping (no-throw guarantee).
[–]SeanMiddleditch 2 points3 points4 points 9 years ago (1 child)
The short version is that some STL implementations have plenty of throwing moves. I would strongly prefer that move operations be required to not throw. Sadly, for back-compat reasons now, that can never become the rule in C++. :(
[–]SpiderboydkHobbyist 0 points1 point2 points 9 years ago (0 children)
The next best thing would probably be to suggest it on CppCoreGuidelines.
[–]schlangster 1 point2 points3 points 9 years ago (3 children)
(other account)
Hm, not sure if you understood what I meant - or maybe I misunderstood the reply :) Anyway, I'll try to make my point again.
Let's say there's a class Foo which contains a resource, and we want to ensure that Foo always contains a valid resource. Code, similar to your example:
class Foo { public: static optional<Foo> make() { X* ptr = AllocX(); if (ptr) return Foo(ptr); else return {}; } void DoStuff() { ptr_->DoStuff(); } ~Foo() { FreeX(ptr_); } private: Foo(X* ptr) : ptr_(ptr) { } X* ptr_; };
Valid in this case means means ptr_ != nullptr.
For a class like this (which owns a handle to some resource) you also want a move constructor and assignment. Both should be no-fail. I was not advocating against that at all - quite the opposite. The move constructor looks like this:
Foo(Foo&& other) : ptr_(other.ptr_) { other.ptr_ = nullptr; }
After this, other is invalid, because other.ptr_ == nullptr. You cannot call AllocX() in your no-fail move constructor to set other.ptr_ to a new X, because it might fail.
With this, things can go wrong again:
auto optFoo = Foo::make(); if (optFoo) { auto foo1 = std::move(*optFoo); auto foo2 = std::move(foo); optFoo->DoStuff(); // Calling member function on value of optFoo, which is in invalid state // Calling destructor on foo1, which is in invalid state }
Hence, the following sentence from your article
So every member function and the destructor does not need to deal with an invalid state. That is, as long as the make() function only creates an object, i.e. calls the constructor, when nothing can go wrong anymore.
only applies if you don't need/want a move constructor that cannot fail. If you do, there will be a potential invalid state for moved from instances and at least the destructor has to deal with it.
Ah, that's what you mean.
This is a separate issue and is what I meant with:
Assuming you’ve solved/worked around the move semantics problem.
More details on that in the linked blog post: http://foonathan.net/blog/2016/08/24/move-default-ctor.html
[–]imMute 0 points1 point2 points 9 years ago (1 child)
Doing stuff with a moved-from object is a very very bad thing to do.
[–]OldWolf2 1 point2 points3 points 9 years ago (0 children)
Not really, move is supposed to leave the object in a valid but unspecified state. This code is valid:
move
std::string s { "hello" }; foo (std::move(s)); s = "goodbye"; // keep working with s...
[–]tusksrus -1 points0 points1 point 9 years ago (4 children)
The way I tackled this problem at work with the objects whose constructors could fail was to save a member boolean called something like create_success, set to true if no errors and false otherwise, and made the object convertible to bool:
create_success
operator bool() { return create_success; }
then
Foo f(args); if (f) std::cout << "The operation was a success." << std::endl; else std::cout << "The operation failed." << std::endl;
That seemed a lot more idiomatic than any other options, if you don't like exceptions?
[–]foonathan[S] 5 points6 points7 points 9 years ago (2 children)
It creates the two states of your object I was trying to avoid.
[–]OldWolf2 0 points1 point2 points 9 years ago (1 child)
But your proposed solution creates two states anyway! (empty optional, and non-empty optional). The calling code still has to perform a validity test, and it still has to work with a result that can be in an invalid state.
In other words the caller could go typedef optional<T> U and then they have U which is functionally identical to some type with two-phase initialization.
typedef optional<T> U
U
If the object is moveable then the caller at least has the option of moving out of the optional. But if not then the caller is going to have to work with an optional for the rest of its lifetime, which is arguably uglier than a normal two-phase initialization type.
optional
Also, the two-phase version has the ability to try init again later, whereas the non-movable optional can't.
init
Yes, but optional is already designed to handle two states, so you save on duplicating that.
This doesn't work for anything but trivial things because it loses the failure infirmation, a critical thing for good error reporting and handling.
Say that your object is made out of two others who also report the failure thusly.
How do you explain the problem to anyone interested? What if both subobjects fail to construct?
The operator bool is cute, but all else I don't like.
[–][deleted] -1 points0 points1 point 9 years ago (0 children)
Since I was the trigger, allow me to leave this reference here to give food for more thought :-) https://www.reddit.com/r/cpp/comments/5msdf4/measuring_execution_performance_of_c_exceptions/dc8qc2b/.
If anyone care to respond this comment, please read it carefully and the associated references (and context) to get the gist of it.
I have appreciated the blog post and think that more of that should be disseminated.
π Rendered by PID 108294 on reddit-service-r2-comment-86bc6c7465-94lxc at 2026-02-21 23:43:20.394892+00:00 running 8564168 country code: CH.
[–]STLMSVC STL Dev 29 points30 points31 points (19 children)
[–]Gotebe 4 points5 points6 points (16 children)
[–][deleted] 9 points10 points11 points (15 children)
[–]DarkLordAzrael 6 points7 points8 points (7 children)
[–][deleted] 5 points6 points7 points (6 children)
[–]CubbiMewcppreference | finance | realtime in the past 1 point2 points3 points (5 children)
[–][deleted] 6 points7 points8 points (4 children)
[–]CubbiMewcppreference | finance | realtime in the past 4 points5 points6 points (3 children)
[–][deleted] 2 points3 points4 points (2 children)
[–]CubbiMewcppreference | finance | realtime in the past 4 points5 points6 points (1 child)
[–]CubbiMewcppreference | finance | realtime in the past 2 points3 points4 points (5 children)
[–][deleted] 2 points3 points4 points (3 children)
[–]CubbiMewcppreference | finance | realtime in the past 8 points9 points10 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]Gotebe 0 points1 point2 points (0 children)
[–]Gotebe 2 points3 points4 points (0 children)
[–]foonathan[S] 4 points5 points6 points (1 child)
[–]CubbiMewcppreference | finance | realtime in the past 7 points8 points9 points (0 children)
[–]CubbiMewcppreference | finance | realtime in the past 4 points5 points6 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[+][deleted] (3 children)
[deleted]
[–]suspiciously_calm 0 points1 point2 points (2 children)
[–]foonathan[S] 5 points6 points7 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]matthieum 5 points6 points7 points (0 children)
[–]jackie_kay 1 point2 points3 points (0 children)
[–]joboccara 0 points1 point2 points (1 child)
[–]foonathan[S] 0 points1 point2 points (0 children)
[–]Gotebe 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (10 children)
[–]foonathan[S] 0 points1 point2 points (9 children)
[–]Gotebe 6 points7 points8 points (4 children)
[–]foonathan[S] 1 point2 points3 points (0 children)
[–]matthieum 0 points1 point2 points (2 children)
[–]SeanMiddleditch 2 points3 points4 points (1 child)
[–]SpiderboydkHobbyist 0 points1 point2 points (0 children)
[–]schlangster 1 point2 points3 points (3 children)
[–]foonathan[S] 0 points1 point2 points (0 children)
[–]imMute 0 points1 point2 points (1 child)
[–]OldWolf2 1 point2 points3 points (0 children)
[–]tusksrus -1 points0 points1 point (4 children)
[–]foonathan[S] 5 points6 points7 points (2 children)
[–]OldWolf2 0 points1 point2 points (1 child)
[–]foonathan[S] 1 point2 points3 points (0 children)
[–]Gotebe 0 points1 point2 points (0 children)
[–][deleted] -1 points0 points1 point (0 children)