37

Should I use noexcept method modifier for getters always in C++11?

I mean simple getters here that just return members. At least in all my getters I have here an exception can't possibly be thrown. One downside is that a getter gets too verbose:

const std::string& getName() const noexcept{ return name; }

The good side as pointed out in Stroustrup's book is that the compiler might do some optimizations here and there.

user3111311
  • 7,583
  • 7
  • 33
  • 48
  • 2
    This is quite related to the usual "should I write (trivial) getters and setters?" question. If your getter is really that simple that you can guarantee that it will stay `noexcept`, then do you really need it in the first place? – juanchopanza Jan 24 '14 at 11:02
  • 1
    @juanchopanza that is another good argument yes. You suggest I have public members? – user3111311 Jan 24 '14 at 11:02
  • Well, if you have a trivial "getter" that you really don't need to have the freedom to change into something more complicated, then yes. The `noexcept` limits that freedom anyway, but not completely. You could still have a getter than does more than return by reference, but still be guaranteed not to throw. – juanchopanza Jan 24 '14 at 11:05
  • @juanchopanza: sure why not... example: complex number library, cartesian and polar coordinates. – Karoly Horvath Jan 24 '14 at 11:05
  • @KarolyHorvath Exactly. I have some geom code somewhere where the underlying coordinate representation can be different. So this requires getters and setters in the interface, and these are sometimes trivial. But that is a particular example. Often you don't need this (and it is up to you to decide how sure you are of this :-)) – juanchopanza Jan 24 '14 at 11:08
  • 1
    Generally, these trivial getter/setter are inlined, so compiler can easily deduce they are `noexcept`. – Jarod42 Jan 24 '14 at 11:20
  • possible duplicate of [When should I really use noexcept?](http://stackoverflow.com/questions/10787766/when-should-i-really-use-noexcept) – Ali Jan 24 '14 at 11:50
  • @user3111311 If you look at the question linked just above, you will see where you might get *some* performance benefit, if you get any at all. Getters and setters are not among them. – Ali Jan 24 '14 at 11:52
  • 1
    For now my opinion is that it's only worth adding on `swap` and special member functions. – Simple Jan 24 '14 at 12:01
  • Trivial getters are a sign of problems in the design. Unless the class is a simple struct then public data members are also a sign of problems. – bames53 Jan 25 '14 at 16:45
  • 2
    @bames53 & juanchopanza: Old question, but I'd challenge that statement. Triviall getters AND setters might be a sign of a problem, but trivial getters alone occure quite naturally. E.g. think about things like `isOpen()`, `size()`, `operator[]`, `getID` and in general, if you want to protect the datamembers in your object from modifications, that would break certain invariants, but still require read access to them. – MikeMB Nov 20 '15 at 18:13
  • 1
    @MikeMB exactly. we want users to be able to read such members, but making them public members would mean the users could also modify them unchecked, which is a terrible idea. – underscore_d Apr 04 '17 at 21:07
  • Apparently, `noexcept` is like `const` (on functions). It is mostly a conceptual thing that makes you think about your code more than give you a very unlikely (but possible) speed up benefit. https://youtu.be/OkgvqjJzH_Y?t=4138 and actually this precise question is asked later https://youtu.be/OkgvqjJzH_Y?t=4279 . – alfC Nov 13 '17 at 14:10
  • @alfC I'm all for keywords that exist to ensure or even just self-document correct semantics, as stating intent is a massively important property of well-written code. That said: It's very much more than conceptual if adding it to a function that was previously able to throw exceptions, which client users depended on catching, & by adding `noexcept` suddenly their program can just `terminate()` instead. *Not* adding `noexcept` before was an (implicit) piece of documentation about the API, just as adding it is. It is also very practical if it means stdlib algorithms can move instead of copying. – underscore_d Oct 06 '18 at 10:45

2 Answers2

33

noexcept is a promise that is very hard to take back. For example, you could later do something as simple as change the return type to std::string (for whatever reason), but because that needs to allocate a copy of the string, it can throw.

So the standard went the way of "add noexcept only when it's necessary or highly beneficial", and I think that's a good rule to follow. The question you need to ask yourself is, will the callers of this method need it to not throw?

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • I'm not sure. This removes the ability of static analyser to validate that this methods really don't throw. And i don't think that throwing on out of memory is ever a good idea, a good reason why java didn't include this. – Lothar Apr 10 '17 at 01:25
  • Java has an `OutOfMemoryError`. – Sebastian Redl Apr 10 '17 at 20:07
  • But like assert it is not tracked by the throw clauses. – Lothar Apr 11 '17 at 04:20
  • 2
    Saying it's hard to remove `noexcept` later is true, because it's part of the public API, which can become difficult to change without breaking client code. Which makes it very weird to use an example that changes the return type from said API *anyway*... If you're already able to do that, why is it at all hard to also remove `noexcept` at the same time? All bets are already off. – underscore_d Oct 06 '18 at 10:35
  • @underscore_d Changing from `const std::string&` to `std::string` will usually not require any client code changes. – Sebastian Redl Oct 06 '18 at 10:40
  • Sure, but is is still an API change and, even if the code as written is the same, will require recompilation, which I think often is bad enough from users' POV. Then adding `noexcept` at the same time requires no changes to the client code either, except that now it may get `terminate()`d instead. – underscore_d Oct 06 '18 at 10:41
  • 1
    It's C++. Pretty much any change whatsoever needs recompilation. And we're not talking about adding noexcept, but removing it, and the problem with that is that it might silently break assumptions and cause UB or just incorrect logic without the compiler noticing. – Sebastian Redl Oct 06 '18 at 10:44
4

If there is a good chance that someone needs this noexcept qualifier, I would add it. If you do not add it, you have more possibilities to change the implementation (remember, this is the usual argument for setter/getter [and I'm not a fan of setter and getters]).

You usually need this "no throw" guaranty, if you need to call this function in a "rollback, recover from error" situation. For example if you want to call it from a destructor then your life is easier if it offers the nothrow guarantee (and noexcept is the modern way of offering that).

So, I wouldn't make a general rule to add it.

Torsten Robitzki
  • 3,041
  • 1
  • 21
  • 35
  • 3
    "rollback, recover from error" -- for example if you want to call it from a destructor then your life is easier if it offers the nothrow guarantee (and `noexcept` is the modern way of offering that). – Steve Jessop Jan 24 '14 at 11:21
  • 1
    @SteveJessop `noexcept` in itself offers no guarantee whatsoever, it only allows direct termination if an exception should happen. – TemplateRex Jan 24 '14 at 12:21
  • 4
    @TemplateRex: that termination is precisely what guarantees that an exception won't escape the function into the caller. It's true that a call to a `noexcept` function can result in termination, but it's *guaranteed* that it won't result in an exception even if the function implementation throws one. I suppose that whether you actually mark `noexcept` on functions that offer the nothrow guarantee depends on whether `noexcept` imposes a performance cost on your compiler -- if it does and you're sure of your code then you might choose to omit it. But you'd hope it doesn't. – Steve Jessop Jan 24 '14 at 12:29