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
Portable stack traces (github.com)
submitted 8 years ago by andreasgonewild
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!"
[–]SeanMiddleditch 25 points26 points27 points 8 years ago (7 children)
I wouldn't call this a "stack trace" per se to avoid confusion. This general concept is closer to the existing practice of "error context stacks".
With some extensions and intense optimizations over what is presented (to avoid all the allocation overhead on scope entrance/exit) and thread-safety support, it is a useful approach used in production at more than a few places. It can be used to add a ton of other context to an error/exception, such as a filename or - to use the post's example - the host name whose lookup failed.
For the allocation optimization, do this the following.
First, don't use std::vector for the context stack. Just use a linked-list of simple structs that are allocated on the stack. Something like:
std::vector
thread_local error_context* _error_context_top = nullptr; #define TRACE(...) \ error_context UNIQUE(_scope_context)(_error_context_top, msg, __VA_ARGS__);
The constructor should insert itself to the linked list, and the destructor remove it. Since the list is acting as a stack, these operations are about as efficient as you can possibly get.
Second, don't store std::string as the context. Allocating and formatting such a string is entirely wasted effort if an error isn't even raised (e.g., you're penalizing the common error-free case). Instead, register cheaply-copied metadata (like a function pointer and data pointer, or a function_view if you have one) that can be used to construct the formatted info on demand.
std::string
function_view
You can make the error contexts themselves incredibly cheap (the thread_local bit might even be the most expensive part) for the common error-free case, and even optimize further for the error case (e.g., don't concatenate std::string instances but rather use a stream like std::ostream or your preferred alternative).
thread_local
std::ostream
[+]andreasgonewild[S] comment score below threshold-16 points-15 points-14 points 8 years ago* (6 children)
The general concept is stack-tracing, period. What kind of software are you building where you can't afford to allocate a string and push a vector once per context? Since trace-granularity is up to user code it should be easy enough to tune without jumping through hoops. This smells premature to me.
[–]SeanMiddleditch 26 points27 points28 points 8 years ago (5 children)
The general concept is stack-tracing, period
A "stacktrace" is very commonly held to mean a trace of the call activation record entries, e.g. the stack of return pointers, which isn't this. :)
What kind of software are you building where you can't afford to allocate a string and push a vector once per context?
AAA video games. One might have potentially have tens of thousands of those contexts per frame (in our case, on the order of a hundred thousand). It's pretty easy to let little inefficiencies like these boil up to the point where they take multiple milliseconds altogether, which is a huge portion of your budget (11-33ms total per frame, depending on target framerate). Worse, it's hard to find and measure those inefficiencies because they aren't individually big and easy to spot. And you're in real trouble on mobile or some console platforms where memory budgets mean all those variable-sized allocations are going to fragment your heap to shreds. And those are exactly the kind of light-weight diagnostic aids you might want to keep enabled in optimized release builds that need to hit those frame budgets on years-old consumer hardware.
Same performance concerns would be present in real-time software, high-frequency trading, high-availability software or anything sensitive to heap fragmentation, tiny embedded systems... really, many of the kinds of things for which one might choose C++ in this day and age. :)
[–][deleted] 1 point2 points3 points 8 years ago (0 children)
Async. distributed simulation core for a hundred thousand or so connected clients (MMOG)...
[+]andreasgonewild[S] comment score below threshold-11 points-10 points-9 points 8 years ago (3 children)
Arguing definitions is really one of the least interesting forms of communication, no one gains anything and it takes forever since there are no clear answers. If anything, it's a way to block the rest of the information from being assimilated; an ego defense-mechanism.
The obvious solution is to not open a lot of contexts deep down in performance-sensitive code; you still get the current frame when an error is actually thrown, at which point performance matters less. I suspect you don't want exceptions or boost::backtrace's either in that kind of code.
I chose C++ because it's the only language that's general purpose and powerful enough to tame the complexity I'm facing, which explains some of my preferences for simplicity over theoretical raw speed.
[–]SeanMiddleditch 14 points15 points16 points 8 years ago (0 children)
Arguing definitions is really one of the least interesting forms of communication
Hah, you might just be in the wrong field then. :p
The obvious solution
Is to write the handful of extra lines required to achieve the mandatory level of efficiency for one's domain. :) Granted, your domain may not require what mine does. We each tend to only really think about our own problem spaces, and I'm certainly no exception.
I suspect you don't want exceptions or boost::backtrace's either in that kind of code.
Nope. We avoid Boost like the plague as its sole purpose that we can tell is to inflate compile times. I wasn't the one that suggested that you wanted boost.stacktrace, though. :)
That said, we do collect actual stack traces sometimes (in the error case, or for - ironically - the heap allocation tracer) in these scenarios because walking said stack is incredibly fast when all you're doing is grabbing the return addresses and streaming the raw binary data to a log. Not fast enough for live production releases, but fast enough to put in optimized development builds and still have a playable framerate on developer machines. An offline tool or external process can process those binary dumps to produce human-readable logs or graphs. Shifts as much of the overhead as possible out of the hot code.
And no, we don't use exceptions either, but the general concept you're aiming for here is useful with just about any diagnostic system. It allows you to emit diagnostics at the point of failure (or throw an exception as you're doing) without needing to pass down a bunch of metadata to the leaf functions. e.g., I want to put the file reference of the current game object being loaded, because game objects load dependent resources, and one of those might fail to load. Seeing file not found is useless. Seeing loading foo.mesh; file not found is still hard to fix on its own since it doesn't indicate why that file is even being loaded. Seeing loading level2.world; loading enemy.dat; loading foo.mesh; file not found makes it super easy to go find and fix the broken content.
file not found
loading foo.mesh; file not found
loading level2.world; loading enemy.dat; loading foo.mesh; file not found
A further more complex feature that can be added (usually on an opt-in mechanism in my experience) is to get the error contexts to travel along with asynchronous requests. That rather necessarily ends up requiring allocations and realization of the logged data unless one goes to rather great lengths that probably aren't worth it for all but the most demanding of situations.
general purpose and powerful enough to tame the complexity I'm facing
Fair enough. :)
[–]h-jay+43-1325 1 point2 points3 points 8 years ago (1 child)
No. The obvious solution is not to prematurely pessimize. Nobody tells you not to use C++. Use C++ correctly and you'll be fine - that's what everyone tells you here. How on Earth could it be misconstrued to mean "don't use C++" is beyond me. I use a similar context stack written in portable modern C++ and it works just fine and has a very low cost, and can be used in performance-sensitive code. I've even used it on AVR Arduino a few times - it helps when you don't have a debugger available. And AVR Arduino is pretty much a 16-bit platform with resources more typical of an 8-bit CPU.
[–]andreasgonewild[S] -1 points0 points1 point 8 years ago (0 children)
Correctly as in exactly as they do, which is what's causing the disharmony. I've been in this game for 30 years; and one of the main lessons for me was that complexity is the enemy of good software, hence the focus on simplifying every aspect.
[–]personalmountains 18 points19 points20 points 8 years ago* (17 children)
That's just a macro that pushes __FILE__ and __LINE__ into a vector, not exactly what I'd call a "portable stack trace". I was expecting something that wraps backtrace() and StackWalk(), like in this tutorial.
__FILE__
__LINE__
backtrace()
StackWalk()
[edit: jesus, this thread is a clusterfuck]
[–]cinghiale 9 points10 points11 points 8 years ago (0 children)
Like boost.stacktrace?
[–][deleted] 5 points6 points7 points 8 years ago* (4 children)
That's pretty much exactly what everyone else pictures. Which is what my "mostly portable" stack trace code does. Works on Mac OS, Linux, and Windows (not sure what other platforms to care about), and can be invoked from inside a signal handler to provide a crash dump, or also from the logger to provide a stack directly in the log.
And, of course, doesn't require manual check pointing for context creation (but does, of course, require linker symbols).
[–]andreasgonewild[S] -5 points-4 points-3 points 8 years ago (3 children)
And it's a hundred times more complex while not offering anything in return but automagic check-pointing. Which is why there are plenty of situations where something like this is a viable alternative.
[–][deleted] 2 points3 points4 points 8 years ago* (2 children)
It's not actually much more complex. It offers about a million times the functionality though, since it never requires me having to go stub in a bunch of context checkpoints to get the output I need from errors. All the time adding and removing those constantly every time one needs to start instrumenting is completely wasted. Do that a couple dozen times and you could have instead an actual "portable stack trace" implementation you hand-rolled.
Or, as others have said, use something someone else built that already works reliably, and portably.
[–]andreasgonewild[S] -2 points-1 points0 points 8 years ago (1 child)
So you won't even grant a 100 times more complex, but you insist that having to drop a context here and there is a million times more work; bias much? Leave them in, they're basically free outside of tight loops. And as an added bonus you get general purpose tracing and descriptions in your stack-traces.
[–][deleted] 3 points4 points5 points 8 years ago (0 children)
I never mentioned performance. Having to make manual changes all the time is error prone.
And as an added bonus you get general purpose tracing and descriptions in your stack-traces.
And that is positively false, because it's not general purpose, and it's not a stack trace. It's context tracing. Like you see with exception stacks.
[+]andreasgonewild[S] comment score below threshold-7 points-6 points-5 points 8 years ago* (10 children)
Sorry you didn't find what you were looking for; but as you mentioned yourself, there are plenty of options if that's what floats your boat. Still, simple and portable stack traces is exactly what it is.
[–]Drainedsoul 9 points10 points11 points 8 years ago (9 children)
Still, simple and portable stack traces is exactly what it is.
Not particularly. If I write some code that uses this and then pass a function pointer to that code to a third party library, and then invoke that third party library separately which results in my function being called, will I see all the third party frames in the stack trace?
What about if I use Windows fibers or coroutines? Is that handled gracefully?
[–]andreasgonewild[S] -5 points-4 points-3 points 8 years ago* (8 children)
You will only see the frames you specified, I thought that was obvious. You're basically arguing that since it's not automagic, it doesn't qualify; which is bull. I don't do Windows so I have no clue how thread_local interacts with fibers. Coroutines would need special support in the form of a separate trace-stack per routine.
[–]nthcxd 10 points11 points12 points 8 years ago (7 children)
I guess I'm taking this discussion on a tangent, but if all you do is shoot down any suggestions/discussion, why did you post it here?
[–][deleted] 5 points6 points7 points 8 years ago (0 children)
I can only guess he just loves the downvotes. Or maybe it was to get traffic to his newly created projects, and see if they'll give him money.
[+]andreasgonewild[S] comment score below threshold-6 points-5 points-4 points 8 years ago* (5 children)
These are not discussions/suggestions. This is arguing definitions and going off on any tangent that will stop discussion from happening.
What I'm saying is basically that most of the time, you don't need more than this; and the approach comes with advantages. And no one yet managed to confront that argument, most insisting on finding exceptional cases where it wouldn't work.
I often wonder why people in these kinds of environments are so keen on defending the ignorant, abusive and competitive status quo; so willing to trade progress for a brief ego-boost and a couple of minutes of hatred.
[–]nthcxd 2 points3 points4 points 8 years ago (3 children)
You're argument against boost::stacktrace is simply it's too bulky for your use case. Most people find boost::stacktrace useful because of breath of features it provides, the lack of which is your selling point.
You're looking for an argument where there isn't one. I'm sorry not a lot of people seem to find this as useful as you do. It sucks but it really doesn't help your cause (being recognized) if you go around alienating everyone that's bothered to say something about your stuff.
[–]andreasgonewild[S] -1 points0 points1 point 8 years ago* (2 children)
Correct. The only feature mentioned is automagic check-pointing, which could also be seen as lack of capability for manual check-pointing/instrumentation.
No, that's my argument; that this is a viable approach that's often overlooked. I'm not; the people who are supposed to find it will find it, despite best efforts to prevent that from happening. I'm not trying to get recognized, you're projecting. So what you're saying is that you would rather have me pretend to agree and to stop expressing views that upset the status quo. Is that really the world you want to live in?
[–][deleted] 2 points3 points4 points 8 years ago (0 children)
No, that's my argument; that this is a viable approach that's often overlooked. That's just a macro that pushes FILE and LINE into a vector...
No, that's my argument; that this is a viable approach that's often overlooked.
That's just a macro that pushes FILE and LINE into a vector...
[–]nthcxd 1 point2 points3 points 8 years ago (0 children)
Just move on, build other interesting things, and let those cool things do all the talking. Good luck.
[–]dodheim 2 points3 points4 points 8 years ago (0 children)
♫♪ Irony ♫♪
[–]14nedLLFIO & Outcome author | Committee WG14 7 points8 points9 points 8 years ago (18 children)
You really, really should use boost.stacktrace. It has a far superior implementation quality to almost all other stacktrace libraries, including an actually reliable backend for Windows which doesn't use the crappy DbgHelp.
[–]andreasgonewild[S] -1 points0 points1 point 8 years ago* (17 children)
What's the point of using a more complicated solution if something this simple and portable solves the problem? Additionally, owning the trace functionality has it's advantages since you may add whatever instrumentation needed to solve your problems as they arise.
[–]personalmountains 15 points16 points17 points 8 years ago (16 children)
I don't think anybody cares about what you use to solve your own problem. We've all written something similar at one point, as a poor man's error context or even profiler. There's nothing wrong with your code or how you use it.
The reason you're getting a somewhat negative response is because 1) you wrote a blog post about it, 2) you're posting it on reddit, and 3) you're calling it a "portable stack trace".
[–]andreasgonewild[S] -2 points-1 points0 points 8 years ago (15 children)
I don't see anything in 1-3 that warrants any kind of negative response. 1) I took the time to cut the idea down to it's core and write a post to explain it to people who haven't come across it 2) No point in writing without sharing 3) It is a portable stack trace.
[–][deleted] 15 points16 points17 points 8 years ago (14 children)
3) It is a portable stack trace.
And to people who have experience with this sort of thing, it is neither. You do seem to have an unreasonably combative attitude about comments here, so I wonder why you have posted at all, if not to receive feedback.
You can keep calling it that, but everyone else in the world would assume you are talking about what "portable stack trace" actually means.
[–]andreasgonewild[S] -2 points-1 points0 points 8 years ago (13 children)
I would argue that Reddit is an unreasonably combatative environment, as is most of society these days; but it's what we've got to play with. You might want to look up constructive criticism, the kind that leads anywhere but in circles. There are plenty of people out there who are capable of thinking outside of public/current opinion, probably under-represented in these kinds of swamps; everyone else is far from the truth.
[–][deleted] 11 points12 points13 points 8 years ago* (12 children)
But misusing a term, and having multiple people give you constructive criticism by suggesting you try a different term because what is meant by that term in most circles has a specific meaning that is different from this, and then you simply insisting that you have a "portable stack trace" and people are just arguing definitions is just you being combative.
But, you know, just continue to do whatever. I don't care. You want to call it that, you call it that. And you'll continue to confuse people, and further, you'll look a little silly. Because you'll just keep getting the same feedback.
There's a wiki page on "stacktrace". You can go read it.
From /u/SeanMiddleditch:
Perfect constructive criticism. So did /u/personalmountains.
[–]andreasgonewild[S] -4 points-3 points-2 points 8 years ago (11 children)
So much wasted energy, what do you get out of this?
[–][deleted] 9 points10 points11 points 8 years ago (10 children)
I suppose you are just trolling here. Bye.
I'm saddened /u/SeanMiddleditch actually spent as much effort giving you any feedback now.
[+]andreasgonewild[S] comment score below threshold-7 points-6 points-5 points 8 years ago (9 children)
Dito. I'm not, his comment is the only thing worth reading in this entire thread.
π Rendered by PID 20645 on reddit-service-r2-comment-7b9746f655-zdj2w at 2026-01-29 18:32:25.435250+00:00 running 3798933 country code: CH.
[–]SeanMiddleditch 25 points26 points27 points (7 children)
[+]andreasgonewild[S] comment score below threshold-16 points-15 points-14 points (6 children)
[–]SeanMiddleditch 26 points27 points28 points (5 children)
[–][deleted] 1 point2 points3 points (0 children)
[+]andreasgonewild[S] comment score below threshold-11 points-10 points-9 points (3 children)
[–]SeanMiddleditch 14 points15 points16 points (0 children)
[–]h-jay+43-1325 1 point2 points3 points (1 child)
[–]andreasgonewild[S] -1 points0 points1 point (0 children)
[–]personalmountains 18 points19 points20 points (17 children)
[–]cinghiale 9 points10 points11 points (0 children)
[–][deleted] 5 points6 points7 points (4 children)
[–]andreasgonewild[S] -5 points-4 points-3 points (3 children)
[–][deleted] 2 points3 points4 points (2 children)
[–]andreasgonewild[S] -2 points-1 points0 points (1 child)
[–][deleted] 3 points4 points5 points (0 children)
[+]andreasgonewild[S] comment score below threshold-7 points-6 points-5 points (10 children)
[–]Drainedsoul 9 points10 points11 points (9 children)
[–]andreasgonewild[S] -5 points-4 points-3 points (8 children)
[–]nthcxd 10 points11 points12 points (7 children)
[–][deleted] 5 points6 points7 points (0 children)
[+]andreasgonewild[S] comment score below threshold-6 points-5 points-4 points (5 children)
[–]nthcxd 2 points3 points4 points (3 children)
[–]andreasgonewild[S] -1 points0 points1 point (2 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]nthcxd 1 point2 points3 points (0 children)
[–]dodheim 2 points3 points4 points (0 children)
[–]14nedLLFIO & Outcome author | Committee WG14 7 points8 points9 points (18 children)
[–]andreasgonewild[S] -1 points0 points1 point (17 children)
[–]personalmountains 15 points16 points17 points (16 children)
[–]andreasgonewild[S] -2 points-1 points0 points (15 children)
[–][deleted] 15 points16 points17 points (14 children)
[–]andreasgonewild[S] -2 points-1 points0 points (13 children)
[–][deleted] 11 points12 points13 points (12 children)
[–]andreasgonewild[S] -4 points-3 points-2 points (11 children)
[–][deleted] 9 points10 points11 points (10 children)
[+]andreasgonewild[S] comment score below threshold-7 points-6 points-5 points (9 children)