-2

Just started playing around with SDL2 again this morning, although the fact that SDL is used in the example here is not relevant, for the purposes of this question we could consider any framework / toolkit / library which can produce runtime errors.

Started writing the following code:

if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
    std::cerr << SDL_GetError() << std::endl;
}

I don't think this is very good.

  • This style of outputting messages to cerr is not easy to change in future if we needed to do so. If we want to print error messages to a file instead, then we would have to find all occurances of this code snipped and change cout to a file. This would clearly not be practical or easy.

  • It isn't very flexible. Perhaps we might want to have errors, warnings, and general info messages. They might need to go to different places depending on how the user has configured our program. Perhaps some users want to see all warnings and info and others want to see nothing but the most "critical" error messages.

From working on other projects I have seen things used which look like macros.

For example, the following sticks in my mind:

DT_THROW_IF(condition, "message");

My assumption is that this is implemented as a macro. If condition evaluates to true then message appears in the output. (cout/cerr)

The use of a macro like this might go some way to addressing the above issues, however I have heard that it is not good practice to make extensive uses of macros.

  • What are some best practices for error message and warning message handeling in C or C++ programs? What good solutions are available and when is their use appropriate?
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • 1
    Don't add both c++ and c tags, they are quite different. – llllllllll Feb 07 '18 at 12:43
  • Voting to close as "Opinion Based". As you illustrate in the question there are many ways to achieve this none objectively better than the other. – Richard Critten Feb 07 '18 at 12:47
  • 3
    Maybe more appropriate for [SoftwareEngineering.SE]? –  Feb 07 '18 at 12:49
  • I use a logger like boost:log in nearly all of my applications. – drescherjm Feb 07 '18 at 12:55
  • @RichardCritten That's not true. The example I gave is pretty much objectively worse in all possible metrics except for simplicity. – FreelanceConsultant Feb 07 '18 at 12:56
  • *This style of outputting messages to `cerr` is not easy to change in future ...* True, While you can redirect the output to a file, that has huge disadvantages, too. Your process becomes tied to the log file. You can't rotate such a log file, you can't reliably truncate such a log file if it fills up your disk, nor can you delete the log file (on Posix-type systems, even if you do *unlink* its directory entry, it'll remain on disk, growing...) – Andrew Henle Feb 07 '18 at 13:20
  • This is too broad and leads to opinion-based answers. As for your concern, you should simply be writing to an `ostream` object and then set that to `cerr` or whatever else is suitable, elsewhere. If you need more detailed error handling, implement an error handler class. Icky macros is not a good idea neither in C nor C++. – Lundin Feb 07 '18 at 13:47
  • @JETM when referring other sites, it is often helpful to point that [cross-posting is frowned upon](https://meta.stackexchange.com/tags/cross-posting/info) – gnat Feb 07 '18 at 13:52
  • @Lundin I don't see how there is any opinion in "best practices". The vast majority of people will agree on whether a common or standard method is suitable. Anyone who disagrees in this hypothetical situation is probably just wrong. – FreelanceConsultant Feb 07 '18 at 19:24
  • @user3728501 There is no common de facto standard, why it is opinion-based. Asking for all the possible ways to do this, in two different programming languages, is too broad. – Lundin Feb 08 '18 at 07:29
  • The tag is for C and C++ languages. – FreelanceConsultant Feb 08 '18 at 15:28

1 Answers1

3

Using macros for this is good practice. It enables implicit use of __FILE__, __LINE__, __func__, etc. For example, BOOST_THROW_EXCEPTION bundles up all this metadata about the exception for you.

Personally I always create a project-specific set of macros similar to your DT_THROW_IF. This allows capturing the full metadata at the throw site without clutter. And if the macros are constructed properly, there is no downside, and they rarely need to be modified or maintained.

As an example of what I'm talking about, here's one open source project of mine which has such macros: https://github.com/jzwinck/pccl/blob/master/throw.hpp - they are production tested (with GCC) and you're welcome to use them.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 1
    For all template & object foolery of C++ it never quite superseded macros. Whole talk about bad-bad macros is just to deter novice programmers from overusing them. – Uprooted Feb 07 '18 at 13:24
  • Fun exercise: come up with logging macros like yours for older compilers that don't implement vararg macros, but that still capture `__FILE__`, `__LINE__`, and `__function__`. – Andrew Henle Feb 07 '18 at 13:24
  • @AndrewHenle: The macros I linked rely on C++11 (variadic templates), not just variadic macros. I would be surprised to find a compiler that supports the former but not the latter...but probably there is one. – John Zwinck Feb 07 '18 at 13:33
  • What do `__FILE__` and `__LINE__` have to do with macros? What is `__function__`, did you mean standard `__func__`? None of these depend on the pre-processor. – Lundin Feb 07 '18 at 13:49
  • @Lundin: Try to make an exception throwing function without macros which propagates the throw-site's `__FILE__` and `__LINE__` info. – John Zwinck Feb 07 '18 at 13:51
  • 1
    @Lundin Functions and other abstraction tools are not inlined in the source where the error should be thrown. If you use `__LINE__` in a `report_error` function, then `__LINE__` will refer to that function, not the caller, as you would expect from an error report. With that said, we might get `std::source_location` eventually... – KABoissonneault Feb 07 '18 at 13:55
  • @JohnZwinck Well there's `assert` but I get your point now. – Lundin Feb 07 '18 at 14:05