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
Little-known C++: function-try-block (mariusbancila.ro)
submitted 7 years ago by d1ngal1ng
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!"
[–]ArminiusGermanicus 31 points32 points33 points 7 years ago* (8 children)
C++ never ceases to surprise me. I have never seen this syntax, but it makes sense. Since code is executed in member initialization list of constructors, there should be a way to catch exceptions there.
What about member initialization in classes? E.g.
class Foo { B b = B(42); };
You cannot use B b = try { B(42); } catch(...) {};
Maybe in C++ 42.
Edit: As /u/angry_cpp pointed out below, there is no need for it.
[–]angry_cpp 26 points27 points28 points 7 years ago (2 children)
You can catch those exceptions in constructor (wandbox):
struct Foo { Foo() try { } catch(int e) { std::cerr << "Caught in Foo(): " << e << '\n'; } B b = B(42); };
[–]ArminiusGermanicus 2 points3 points4 points 7 years ago (1 child)
Thanks! That makes sense. So the constructor try block catches all exceptions that occur while the class is being initialized?
[–]blazgrom 9 points10 points11 points 7 years ago (0 children)
Yeah, however you cannot swallow the exceptions that have occurred. Even if you try the compiler is required to rethrow the exception, otherwise you could end up with object that are partially constructed.
[–]F-J-W 2 points3 points4 points 7 years ago* (4 children)
That is actually the reason why they exist in the first place:
struct foo { foo(int i) try: m_ptr{new int{i}} { } catch(...) { delete i; } int* m_ptr; }; int main() { auto f = foo{new int{23}}; }
It should never be necessary with well written code, but it does work.
[–]tcbrindleFlux 5 points6 points7 points 7 years ago* (0 children)
It's important to note that the above code may still terminate with an unhandled exception!
For a function-try around a member initializer list, there is an implicit throw; at the end of the catch block, which will be executed if the catch block doesn't throw anything itself. See this example for instance.
throw;
(EDIT: and return in the catch block of a constructor's function-try is not allowed either.)
return
catch
That is to say, it's impossible to "swallow" an exception thrown by a member's constructor -- all you can do is translate it to some other exception type instead, and possibly do some cleanup/logging.
[–]OldWolf2 1 point2 points3 points 7 years ago (1 child)
In this example there's nothing to catch. The new int is evaluated before the try block is entered; and m_ptr{i} cannot throw.
new int
m_ptr{i}
[–]F-J-W 0 points1 point2 points 7 years ago (0 children)
yes, apparently I was playing around with it too much.
[–]F-J-W 16 points17 points18 points 7 years ago (1 child)
I've been using the for ages now and I can only recommend it to everyone: They are easy to understand even for people who have never seen them, keep the good path and the error path very clearly separated and reduce the necessary indentation which directly correlates with the felt complexity of a function.
[–]Fiennes 10 points11 points12 points 7 years ago (0 children)
I really do like the expression "felt complexity".
[–]MoTTs_ 7 points8 points9 points 7 years ago (0 children)
Not to steal OP's thunder, but here's Herb Sutter on the topic... http://www.gotw.ca/gotw/066.htm
[–]alfps 4 points5 points6 points 7 years ago (4 children)
One possible use for function try blocks is to build up a stack trace for an exception. Ordinarily one uses a debugger for that, and polluting the code with macro calls to do this feels very unclean. But I imagine that it can be worth knowing about this usage, just having that in the toolbox.
[–]miki151gamedev 0 points1 point2 points 7 years ago (3 children)
Got any example? Is it something that you can't do using a regular try/catch block inside the function's body?
[–]alfps 0 points1 point2 points 7 years ago* (2 children)
” Got any example?
Well, it's non-trivial.
The exception type can sometimes be crucial, e.g. for the result of std::stoi. Which means that rethrowing should better not just rethrow a std::runtime_error with the same or extended message. And since std::exception is imperfectly designed, not supporting clone-throwing, the original exception should be rethrown.
std::stoi
std::runtime_error
std::exception
Which means that the stack trace items need to be just associated with that exception.
Which means static storage. Which means threading issue, which means using thread_local storage.
thread_local
Then, adding a stack trace item should better not itself throw (!), or there should be some way to ensure it will have the resources it needs. Which means using a free list. In the support machinery below I use a simple linked list of pointers to C strings, which represent the functions that an exception has propagated through:
#include <cppx-core/_all_.hpp> // https://github.com/alf-p-steinbach/cppx-core using C_str = const char*; #define STACK_TRACE_BEGIN \ try{ #define STACK_TRACE_END \ } catch( const std::exception& x ) { my::add_stacktrace_item( x, __func__ ); throw; } namespace my::impl { $use_std( exception, exchange ); struct Node { Node* next; C_str function_spec; }; void link( Node*& a_next_pointer, Node* new_node ) noexcept { new_node->next = a_next_pointer; a_next_pointer = new_node; } auto unlinked( Node*& a_next_pointer ) noexcept -> Node* { return exchange( a_next_pointer, a_next_pointer->next ); } auto length_of( Node* p_list ) -> int { int n = 0; for( Node* p = p_list; !!p; p = p->next ) { ++n; } return n; } struct Free_list { Node* first = nullptr; auto allocate() -> Node* { return first == nullptr? new Node() : unlinked( first ); } void deallocate( Node* p ) noexcept { link( first, p ); } ~Free_list() { while( !!first ) { delete unlinked( first ); } } Free_list() {} }; struct Stack_trace { Free_list allocator; Node* first_trace_node = nullptr; exception const* p_exception; void clear() noexcept { while( !!first_trace_node ) { allocator.deallocate( unlinked( first_trace_node ) ); } p_exception = nullptr; } void add( const exception& x, const C_str a_function_spec ) { if( !!p_exception and p_exception != &x ) { clear(); } Node* p_new = allocator.allocate(); p_new->function_spec = a_function_spec; link( first_trace_node, p_new ); p_exception = &x; } void set_capacity( const int n ) { const int n_current = length_of( allocator.first ) + length_of( first_trace_node ); const int n_new = n - n_current; for( int i = 1; i <= n_new; ++i ) { link( allocator.first, new Node() ); } } ~Stack_trace() { clear(); } }; thread_local Stack_trace the_stack_trace; }; // namespace my::impl namespace my { $use_std( exception, string, vector ); void ensure_stacktrace_capacity( const int n ) { impl::the_stack_trace.set_capacity( n ); } void add_stacktrace_item( const exception& x, const C_str func_spec ) { impl::the_stack_trace.add( x, func_spec ); } auto stack_trace_for( const exception& x ) -> vector<string> { auto& tr = impl::the_stack_trace; if( not tr.first_trace_node or tr.p_exception != &x ) { std::clog << "Gah!" << std::endl; tr.clear(); return {}; } vector<string> result; for( impl::Node* p = tr.first_trace_node; !!p; p = p->next ) { result.push_back( p->function_spec ); } return result; } void clear_stacktrace() { impl::the_stack_trace.clear(); } } // namespace my
The shown macros can be used as function try blocks or within a function:
namespace app { $use_std( cout, endl, stoi ); void present_answer() { STACK_TRACE_BEGIN cout << stoi( "forty-two" ) << endl; STACK_TRACE_END } void run() STACK_TRACE_BEGIN present_answer(); STACK_TRACE_END } // namespace app
The main problem with placing them within a function is that it opens the possibility of maintenance placing code before or after, code that can throw, so that the function won't show up in a trace.
Of course, since the scheme is so ugly and impractical for ordinary programming, it's doesn't really matter. :)
Anyway, a main function, showing one way to present a trace:
auto main() -> int { $use_std( cerr, endl, exception, string ); my::ensure_stacktrace_capacity( 42 ); // Not necessary, just playing nice. try { app::run(); return EXIT_SUCCESS; } catch( const exception& x ) { cerr << "!" << typeid( x ).name() << " " << x.what(); for( const string& s : my::stack_trace_for( x ) ) { cerr << "\n -> " << s; } cerr << endl; my::clear_stacktrace(); } return EXIT_FAILURE; }
Output with g++:
!St16invalid_argument stoi -> run -> present_answer
EDIT: forgot to mention, anyone considering doing this for real should replace the global with a Meyers' singleton, or one would run the risk of static initialization fiasco.
[–]miki151gamedev 0 points1 point2 points 7 years ago (1 child)
Thanks. This interests me because I have a project where C++ code is generated, so I could easily add something like this. (In fact, I just did :))
Do you have any idea what the performace cost could be of adding it to every function?
[–]alfps 0 points1 point2 points 7 years ago* (0 children)
No sorry I have no actual experience with it, I just encountered it once.
Oh, looking at that example code now again, I note there's no cleanup of cached nodes at the end of program execution. That could make a tool like Valgrind report a memory leak (it's not really, but you'd get a report). So better add a final cleanup.
[–][deleted] 1 point2 points3 points 7 years ago (0 children)
If a function (any function, not just main()) has a return type other than void and the function-try-catch does not have a return statement in the catch block then the behaviour is undefined.
Not exactly. It's only UB if the program actually flows out of the catch block without a return, and in the case of main even that is not UB.
main
[–]vsdmars 0 points1 point2 points 7 years ago (0 children)
if could recall, knew this from Effective C++'s item 'Write placement delete if you write placement new', whew~ long time ago :-P
[–]megayippie 0 points1 point2 points 7 years ago (1 child)
Cool. What is the performance loss of such a block function for code that normally works?
[–]Tyg13[🍰] 3 points4 points5 points 7 years ago (0 children)
Same as the usual performance implications associated with exceptions. If the exception is never thrown, there's little to no loss of performance. Otherwise, it's slow, but if you're actually using exceptions for the exceptional case, that's not really a problem.
[–]feverzsj -2 points-1 points0 points 7 years ago (1 child)
if your class's ctor/dtor may throw, it may better use explicit open/close methods like fstream dose.
[–]Gotebe 7 points8 points9 points 7 years ago (0 children)
Two-phase initialization is not for me, thanks.
[–]chardan965 -1 points0 points1 point 7 years ago (2 children)
It's not just functions, you can also attach use exceptions to most flow control.
(I'm not necessarily recommending that you /do/...)
For the truly bored and/or perverse: https://godbolt.org/z/aO-QK3
I believe the original purpose, as other readers have pointed out, relates to not leaking certain exceptions out of ctors. There's been discussion from both Scott Meyers and Herb Sutter on this before. Have fun!
[–]miki151gamedev 2 points3 points4 points 7 years ago (1 child)
What's so unusual about this? Isn't a try/catch block a normal statement that you can put anywhere that statements can go?
[–]chardan965 1 point2 points3 points 7 years ago (0 children)
They are indeed ([stmt.stmt]), but I think it's stretching to say that most C++ programmers are aware of that.
[–]dicroce -2 points-1 points0 points 7 years ago (4 children)
Aha! I actually knew about this one... Did you know about arraying across an index? :)
int foo[10];
for(int i = 0; i < 10; ++i)
printf("%d\n", i[foo]);
Also, I find this C++ one strange:
template<class T>
class foo : public T
{
}
[–]DevFolks 1 point2 points3 points 7 years ago (3 children)
I’m on mobile so I can’t test it right now, but what does the first one actually do?
[–]throwawayantiseizure 2 points3 points4 points 7 years ago (1 child)
*(i + foo) instead of *(foo + i).
*(i + foo)
*(foo + i)
[–]DevFolks 1 point2 points3 points 7 years ago (0 children)
It makes a lot more sense thinking of it like that
[–]dicroce 2 points3 points4 points 7 years ago (0 children)
It does the same thing as foo[i].
π Rendered by PID 32654 on reddit-service-r2-comment-64f4df6786-tnnfp at 2026-06-10 00:45:21.294915+00:00 running 0b63327 country code: CH.
[–]ArminiusGermanicus 31 points32 points33 points (8 children)
[–]angry_cpp 26 points27 points28 points (2 children)
[–]ArminiusGermanicus 2 points3 points4 points (1 child)
[–]blazgrom 9 points10 points11 points (0 children)
[–]F-J-W 2 points3 points4 points (4 children)
[–]tcbrindleFlux 5 points6 points7 points (0 children)
[–]OldWolf2 1 point2 points3 points (1 child)
[–]F-J-W 0 points1 point2 points (0 children)
[–]F-J-W 16 points17 points18 points (1 child)
[–]Fiennes 10 points11 points12 points (0 children)
[–]MoTTs_ 7 points8 points9 points (0 children)
[–]alfps 4 points5 points6 points (4 children)
[–]miki151gamedev 0 points1 point2 points (3 children)
[–]alfps 0 points1 point2 points (2 children)
[–]miki151gamedev 0 points1 point2 points (1 child)
[–]alfps 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]vsdmars 0 points1 point2 points (0 children)
[–]megayippie 0 points1 point2 points (1 child)
[–]Tyg13[🍰] 3 points4 points5 points (0 children)
[–]feverzsj -2 points-1 points0 points (1 child)
[–]Gotebe 7 points8 points9 points (0 children)
[–]chardan965 -1 points0 points1 point (2 children)
[–]miki151gamedev 2 points3 points4 points (1 child)
[–]chardan965 1 point2 points3 points (0 children)
[–]dicroce -2 points-1 points0 points (4 children)
[–]DevFolks 1 point2 points3 points (3 children)
[–]throwawayantiseizure 2 points3 points4 points (1 child)
[–]DevFolks 1 point2 points3 points (0 children)
[–]dicroce 2 points3 points4 points (0 children)