Comments for Sutter's Mill
Comment on GotW #4 Solution: Class Mechanics by litb1
You mention that as an alternative the following can be used
complex () = default;
Wouldn’t this leave the two non-class data members uninitialized (as they are default initialized)?
Read More »
Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@Olaf: Thanks. I agree, this is a good place to mention the new C++11 guidance to pass by value if you’re going to make a copy of the parameter anyway. Updated, including not just there but also in the canonical operator+ with a new paragraph and guideline there, so that now we have both of these guidelines in the text:
Guideline: Prefer passing a read-only parameter by const& if you are only going to read from it (not make a copy of it).
Guideline: Prefer passing a read-only parameter by value if you're going to make a copy of the parameter anyway, because it enables move from rvalue arguments.
I’ve also updated the wording of the first of these guidelines in #2 to match this wording.
Note that the new paragraph alludes to my intention to write a new GotW about parameter passing… “how to pass parameters” deserves a GotW all its own, because the C++11 answer is simultaneously different, considerably simpler in the mainstream, and considerably more complex when you want to take full control, than the C++98 answer.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@Marshall: Re const, it doesn’t quite mean that — wait for GotW #6a. Re move from rvalues, yes, that’s part of what I added in the text I added in response to Olaf’s comment.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@litb1: Good point, that’s worth mentioning. Added.
Read More »
Comment on GotW #4 Solution: Class Mechanics by mttpd
(a) Regarding #2 (and given the above comment by Marshall, specifically the aliasing part) — I’m still wondering, wouldn’t pass-by-value be a better fit here, per N3445?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3445.html
Specifically:
“We can change our habits to pass trivially copyable classes of sixteen bytes or less by value. With this approach, complex numbers would primarily be passed by value, not by reference as they are in the class template complex (26.4 Complex numbers [complex.numbers]). This approach avoids aliasing issues, enables removing some indirect references when accessing parameters, but may introduce copying on older platforms.”
I’m guessing this may have something to do with the latter part, stating that the “net performance change is unclear.” However, isn’t this case similarly unclear for pass-by-value for our specific class (given its size and the presumed use for numerical computing, where aliasing might have an important impact on performance)?
I’m kind of interested in this issue personally and somewhat playing the Devil’s advocate here, since so far I’ve been mostly using pass-by-const-reference for all (strictly-)larger-than-scalar types, just want to make sure I’m not missing a potentially important edge case by not expanding this to “small classes” (as in N3445).
(b) Regarding prohibiting inheritance from value types being an overkill — perhaps, but isn’t it precisely addressing the “easy to use correctly, hard to use incorrectly” point?
I’m thinking in terms of the Standard Library containers here (perhaps that’s too much of an association, correct me if I’m wrong) — is it *ever* justified to inherit from one of those?
Read More »
Comment on GotW #4 Solution: Class Mechanics by litb1
I wonder whether there is any way to avoid the redundancy in the default argument for imag and the inclass initializer for it (when defaulting the default constructor). One alternative is constructor delegation
complex ():complex (1.0f) {}
Read More »
Comment on GotW #5: Overriding Virtual Functions by Mikhail Belyaev
Somehow lost a part of my code, the derived class should be like:
class derived: public base { public: using base::f; // this is essential if you mean overloading across class hierarchies void f( const complex<double>& ); void g( int i = 20 ); };
Read More »
Comment on GotW #5: Overriding Virtual Functions by Mikhail Belyaev
1. What do the override and final keywords do? Why are they useful?
These keywords are useful for signaling to the compiler that we actually tried to override something or that something is not a subject for override. The override keyword is significantly useful to avoid errors like “overload instead of override” that tend to happen often in big class hierarchies spread across developers and are very difficult to spot otherwise. The final keyword is useful in an opposite situation — when you don’t want to override (or to be overridden) and you really mean it.
2. This is an example of the abovementioned “overloading instead of overriding” situation.
1) You should avoid overriding and overloading functions at the same time if you don’t REALLY need that. It leads to errors almost every time.
2) You should avoid giving default values to virtual functions’ parameters as this leads to a difference in behavior for normal and polymorphic invoking of these functions, which is a Bad Thing.
3) The base class should have a virtual destr
Taking that into account and assuming that we really need all this overload-override-default-parameter-stuff:
#include <iostream> #include <complex> using namespace std; class base { public: virtual void f( int ); virtual void f( double ); virtual void g( int i = 10 ); }; void base::f( int ) { cout << "base::f(int)" << endl; } void base::f( double ) { cout << "base::f(double)" << endl; } void base::g( int i ) { cout << i << endl; } class derived: public base { public: void f( complex<double> ); void g( int i = 20 ); }; void derived::f( complex<double> ) { cout << "derived::f(complex)" << endl; } void derived::g( int i ) { cout << "derived::g() " << i << endl; } int main() { base b; derived d; base* pb = new derived; b.f(1.0); // calls base::f(double) d.f(1.0); // calls derived::f(std::complex) !! pb->f(1.0); // calls base::f(double) b.g(); // calls base::g(10) d.g(); // calls derived::g(20) pb->g(); // calls derived::g(10) !! delete pb; // This one would be a memleak if we had any data in derived !! }
Changed:
#include <iostream> #include <complex> using namespace std; class base { public: virtual void f( int ); virtual void f( double ); virtual void g( int i); // do not provide a default; inline void g() { g(10); } // provide a new def instead virtual ~base() {}; // provide a virtual destructor }; void base::f( int ) { cout << "base::f(int)" << endl; } void base::f( double ) { cout << "base::f(double)" << endl; } void base::g(int x) { cout << x << endl; } class derived: public base { public: void f( const complex<double>& ); void g( int i = 20 ); }; void derived::f( const complex<double>& ) { cout << "derived::f(complex)" << endl; } void derived::g( int i ) { cout << "derived::g() " << i << endl; } int main() { base b; derived d; base* pb = new derived; b.f(1.0); // calls base::f(double) d.f(1.0); // calls base::f(double) pb->f(1.0); // calls base::f(double) b.g(); // calls base::g() (which calls base::g(10)) d.g(); // calls derived::g(20) pb->g(); // compiler error delete pb; // This one is ok now }
Read More »
Comment on GotW #5: Overriding Virtual Functions by litb1
I think this is an excellent example where the NVI (non-virtual interface) pattern can be applied. Have the function with the default argument be public and non-virtual, and call a private or protected “doG(int i);”-style function that is virtual and overridden by derived classes. For the overloaded function, each could call a `doF (complex )”-style virtual protected/private function.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Chris
Thank you so much for this article. I see so many who make some of these common errors every day, particularly making operators member functions and not taking the first parameter by value in cases like operator+. If they just discovered this article, they would be much better off.
Anyway, I believe you have a small typo:
“For example, if you provide operator++ you would normally also provide operator–.”
These two don’t always match (think: bidirectional iterator, think harder: forward iterator). You can argue that those aren’t the general case, but I would probably go with + and – (even specifying unary or binary if you want).
Read More »
Comment on GotW #5: Overriding Virtual Functions by mttpd
Ad 1: I feel this has been adequately addressed in the previous comments :-)
Perhaps I could just add that “final” has two uses: member-function-wide and class-wide. However, “preventing overriding” is a good general summary of its intent in both cases (inheritance being necessary to enable overriding anyway).
Ad 2: Also agree with the already-made comments.
To expand, and to perhaps somewhat enliven the discussion, I’ll just make some (possibly unorthodox) extra points [mostly concerning part (a)]:
0. For improved modularity & re-usability (and, perhaps less importantly for this case, to also improve compile times), let’s move the class definitions to a separate header file. To help in accomplishing that without issues, I’d preemptively get rid of the using-directive “using namespace std;” and wrap the classes in a distinct namespace.
1.I won’t suggest replacing
base*
with a smart pointer (like, say,
std::unique_ptr<base>
), and I won’t suggest replacing
new
with the relevant smart pointer factory (say,
make_unique<derived>
, assuming C++14 or access to the well-known piece of code :]) to remove
delete
.
Instead, I’d suggest getting rid of the free store allocation entirely! :-)
After all, it’s completely unnecessary for dynamic (run-time) polymorphism — and references work perfectly fine here.
// This point was aptly made and discussed by Bryan St. Amour in his “Need polymorphism? Consider using references” post, although I’m only able to find a reddit reference to it: http://www.reddit.com/r/cpp/comments/vo2zc/need_polymorphism_consider_using_references/
In other words, let’s get rid of this:
base* pb = new derived;
and use this instead:
derived base & rb = d;
so we can get rid of having to do this:
delete pb;
(Make sure to change
pb->
to
rb.
, too).
In this case we even have an extra gain of not having to create another, duplicate object.
In case this was actually necessary, we can just do:
derived another_d;
derived base & rb = another_d;
Note that we get the automatic / scope-based life-time for free, without having to use std::unique_ptr.
2. Since the alternative interface designs are discussed (e.g., NVI) — how about using CRTP and static (compile-time) polymorphism instead?
See:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Curiously_Recurring_Template_Pattern
I can’t see anything that warrants dynamic (run-time) polymorphism here and IMO it brings an extra, unnecessary (and thus unwanted) complexity: I’d take even a potentially long-winded compiler diagnostic any day over debugging code with (avoidable!) run-time pointer chasing and worrying about dangling references/pointers.
It’s true that historically most books/references were presenting pointers and virtuals first, and templates last (or in a footnote, or not at all). This may (incorrectly) lead some to assume that dynamic (run-time) polymorphism is somewhat “easier” or “simpler”. Given that it’s actually more flexible and offers more features (due to late / run-time binding, ordinarily not available via CRTP), one can argue it’s exactly the opposite. While templates (and, by extension, CRTP), may sometimes generate somewhat long-winded diagnostics (however, note that this is much less of a concern with C++11, type-traits, static_assert, and, as a last resort, enable_if; it will hopefully become even less of a concern with concepts lite in C++14), at least we have a higher degree of confidence that a compiled program is correct (with the associated debugging and reasoning about the program sematics becoming simplified as well).
Given the aforementioned advances, shouldn’t the static (compile-time) polymorphism (and CRTP) be *the* default polymorphism in this day and age?
Read More »
Comment on Guru of the Week and the Exceptional C++ Series by GeoffW
This is all great news and I look forward to reading the updates as they come available. I think updating for C++14 is a great idea … for selfish reasons. I recently started a new project and I am definitely finding C++11 is changing my coding style. I often reference GOTW for reminders of good techniques, so having them updated is going to be very good.
Read More »
Comment on GotW #2 Solution: Temporary Objects by GeoffW
I think @Adrian makes some good points about single-exit. It was never about optimisation, or structured programming rules (or not for me), it was about code clarity. In short, simple functions I am happy to have multiple exits, it’s all there in front of you and your are unlikely to miss them when you come back to maintain the function. In longer or more complex functions multiple-exit points can become a problem for maintenance – and any performance advantages in those situations are dubious and would have to be demonstrated. (Of course we all avoid longer and more complex functions when we can, but they do still happen.)
Read More »
Comment on GotW #4 Solution: Class Mechanics by Matt Fioravante
T operator+( T a, const T& b ) { a += b; return a; }
[quote]Guideline: Prefer passing a read-only parameter by value if you're going to make a copy of the parameter anyway, because it enables move from rvalue arguments.[/quote]
In some cases it may actually be better to pass both arguments by reference so that the compiler can take advantage of return value optimization. For simple value types like complex, a 3d vector, or a 4×4 matrix (where the data is an array the class, not dynamically allocated), this is better because there are no move semantics to take advantage of.
T operator+(const T& a, const T& b) { T c = a; c+=a; return c; } Also you can't be fancy and try to do this: [code] return c+=a;
Now the return value is a reference from operator+=() instead of the temporary you created and the compiler may no longer be able to do RVO.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Marshall
To enable RVO, I would be tempted to write this:
T operator+(const T& a, const T& b) { return T { a.r + b.r, a.i + b.i}; }
Read More »
Comment on GotW #4 Solution: Class Mechanics by decourse
Guideline: Prefer passing a read-only parameter by const& if you are only going to read from it (not make a copy of it).
Guideline: Prefer passing a read-only parameter by value if you're going to make a copy of the parameter anyway, because it enables move from rvalue arguments.
Can someone explain to me why this is not an undesirable abstraction leak?
I think it’s defensible in this case, especially since operator+ is trivial. In the general case, I think it’s bad advice to leak information about the way a function is implemented into its interface.
Read More »
Comment on GotW #4 Solution: Class Mechanics by hm
You did not explain why to make the ctor explicit (but you did it explicit in the summary code).
Read More »
Comment on GotW #5: Overriding Virtual Functions by @lb
Hello,
I really long for a ‘real-life’ example of ‘final’ use. Though I fully understand how it works, I still don’t manage to see where, in a design point of view, it can be relevant or even judicious.
Of course, I do not consider ‘value-classes’ since, as mentioned in previous gotw, the final keyword may enforce this semantic (though we could still wonder why avoiding private inheritance which can be considered as an alternative (and debatable) way of composition).
For the references classes, apart for compiler optimisation help, once a class has been designed to be refined, I fail to see a valid reason why stopping this behavior beeing a good design choice (or inheritance was not the most appropriate variation pattern).
Thank’s in advance.
Best regards.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Daryle Walker
Your code doesn’t take constexpr into account, which changes quite a few things.
class complex { public: // Only have to change the component type in one spot using value_type = double; // Constructors complex() = default; constexpr complex( value_type const &r, value_type const &i = value_type{} ) : c_{ r, i } { } //... private: // Member data value_type c_[ 2 ]; };
First, you need a constexpr-marked constructor, and the component-wise one will do quite nicely. Fortunately, you can initialize arrays in the member-initialization part now.
The advice to implement OP in terms of OP= is somewhat bad now due to constexpr. Implementing a non-mutating function in terms of a mutating one disqualifies the former from being constexpr (since the latter can’t). You either have to reverse the dependencies or write them independently:
class complex { public: //... complex & operator +=( complex const &a ) { c_[ 0 ] += a.c_[ 0 ]; c_[ 1 ] += a.c_[ 1 ]; return *this; } // Has to be a friend if you don't have component-level getters friend constexpr complex operator +( complex const &l, complex const &r ) { return {l.c_[0] + r.c_[0], l.c_[1] + r.c_[1]}; } //... };
I was going to go the reversed-dependency route, but I had a epiphany about the “independent” route. The two operators look unconnected, but notice that each one is implemented in terms of the corresponding element-level operator. If the element-level operators are connected, then the current ones will be indirectly connected. So the old advice is like a hobgoblin’s foolish consistency (or something).
[I'll have some more posts, assuming this code.]
Read More »
Comment on GotW #4 Solution: Class Mechanics by Daryle Walker
In my previous post, note that the component-wise constructor is not explicit. That is intentional. Explicit constructors are for configuration parameters, while implicit ones are for equivalency (either conversion and/or component-wise). It’s like std::vector: the size-setting constructor is explicit, while the iterator-pair and initialization-list ones aren’t. In C++03, the decision for making constructors explicit only mattered for ones with a single-argument mode; now it’s for all constructors. We moved that model to multivalued initialization, whether by std::initialization_list, variadic arguments, or regular constructors with several arguments.
Another way to look at it is that complex numbers are a natural upgrade for real numbers, so having a non-explicit converting constructor makes sense.
I have a separately-defined default constructor, marked “default.” I could have incorporated it into the component-wise/converting constructor, but I wanted distinct semantics. When the value_type is trivial (and since it’s double, it is), this constructor upgrades the class from trivially-copyable to trivial. This lets default-set, but not value-initialized, complex objects have random garbage bits. This is a GOOD thing. The real and imaginary components are independent; there’s no invariant on either for the class or each other. Letting complex be a trivial type means it can play around with C-level routines.
The complex class is also standard-layout. This allows other kinds of C-level play. Since I changed the components from being separate members to a two-element array, I can exploit the same complex array-of-2 reinterpretations the standard wants for std::complex. (The standard expects the reinterpetation to work for an array-of-complex array-of-twice-the-reals, but I can’t do that unless there’s no trailing padding. That can only be done if the compiler supports a Pragma forcing the lack of padding.)
The complex class is POD since it’s both trivial and standard-layout.
The default constructor can’t be constexpr since it’s set to be trivial. A constexpr constructor has to be code-full for use in constant expressions, but the point of a trivial constructor is that it’s code-less!
Read More »
Comment on GotW #4 Solution: Class Mechanics by Matthew Fioravante
@Marshsall:
You don’t need to create a temporary in the return statement for RVO, at least not on modern versions of gcc. Creating a temporary on the stack and returning it later works just fine.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Marshall Clow
>> You don't need to create a temporary in the return statement for RVO, at least not on modern versions of gcc.
I’ll take your word for it – but there are other compilers in the world besides gcc.
Besides, the more I look at that code, the more I like it – it says very clearly what the routine does: “Return a new complex object whose value is the sum of the two parameters ‘a’ and ‘b’”
Read More »
Comment on GotW #4 Solution: Class Mechanics by Daryle Walker
Besides having the arguments in the wrong order, and returning void, the output routine has another problem. Not only is taking (and returning) references to streams is suggested, it’s required! Streams are explicitly not copyable. (This was uncertain in C++03, but made definitive in C++11.)
The stream classes are now templates, making them unsuitable with stuff marked virtual. You would either have to ignore any version of streams besides char, or set up a complex network that works around the virtual/template boundary.
I disagree with a “print” function for another reason. It’s duplicitous; it does the EXACT SAME thing as the stream operator. Why would you ever need both? Can you think of a situation that you would need “print” instead of the operator? Users might get confused, think that there’s some subtle difference, but there wouldn’t be one. You don’t need “print” for access; the stream operators should work on publicly accessible data, resorting to friend access if there’s not enough getters. The output streamer should print enough public information that the input streamer can read it back and create/construct an equivalent copy.
class complex { public: //... template < typename Ch, class Tr > friend basic_ostream<Ch, Tr> & operator <<( basic_ostream<Ch, Tr> &o, complex const &c ) { return o << '(' << c.c_[0] << ',' << c.c_[1] << ')'; } //... };
You shouldn’t actually implement the output-streamer this way; the width modifier would apply only to the first section (the “(“) and spew everything else to the stream as-is. Like std::complex, stream the five sections to a string then print the string.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Daryle Walker
Why did I change the component implementation from two value_type objects to an array of two objects?
1. Why not? Especially since C++11 allows arrays to be put in the member-initialization list
2. It’d only be a problem if the member(s) were directly exposed, but we’re hiding them. Your implementation for the accessors can change to match how the data is stored.
3. The components are guaranteed to be packed, so since the class is also standard-layout, we can reinterpret between a complex and an array-of-two-doubles for some kinds of C-level fun. (We can’t do array-of-complex and array-of-twice-the-doubles reinterpretations unless we can guarantee no rear padding somehow.)
4. We can do this:
class complex { public: //... friend constexpr auto begin( complex const &c ) noexcept -> value_type const * { return &c_[0]; } friend constexpr auto end( complex const &c ) noexcept -> value_type const * { return begin(c) + 2; } // Do the non-const versions, maybe with const_cast... friend void swap( complex &a, complex &b ) noexcept(???) { std::swap(a.c_, b.c_); } //... };
And now it will automatically work with range-for! (The swap isn’t there for any reason but to show the new routine in the standard for built-in arrays.) Heck, we can add tuple support:
class complex { public: //... template < std::size_t I > friend auto get( complex const &c ) noexcept -> value_type const & { static_assert( I < 2u, "Index out of bounds" ); return c.c_[ I ]; } template < std::size_t I > friend auto get( complex &c ) noexcept -> value_type & { return const_cast<value_type &>(get<I>( const_cast<complex const &>(c) )); } template < std::size_t I > friend auto get( complex &&c ) noexcept -> value_type && { return std::forward<value_type>(get<I>( c )); } //... }; //... namespace std { struct tuple_size<my::complex> : integral_constant< size_t, 2u > { }; template < size_t I > struct tuple_element< I, my::complex > { static_assert( I < 2u, "Index too large" ); using type = my::complex::value_type; }; }
Read More »
Comment on GotW #5: Overriding Virtual Functions by Barry
@Mikhael, isn’t d.g() supposed to call derived::g(10), not derived::g(20)? Can’t override default values.
Read More »
Comment on GotW #5: Overriding Virtual Functions by muxecoid
Previous comments already say that “You should avoid overriding and overloading functions at the same time if you don't REALLY need that. It leads to errors almost every time”.
The easy way to remember this rule is to think of every virtual function as interface definition. And if you have an interface you want it to be well (strictly) defined. It means for every function you know what exactly it accepts, without maybes.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Dave Harris
Point 8, “Ignoring the sake of argument”, looks like an editing error. I think you mean, “Ignoring the argument” and were thinking of “For the sake of argument”. Not important, but probably should be fixed if those words might make it into print.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Herb Sutter GotW 4: Class Mechanics | musingstudio
[…] Herb Sutter’s GotW 4 on class mechanics is a treasure trove of best practice. It includes handy examples and canonical signatures for operator<<, operator+ and the pre/post-increment operators. […]
Read More »
Comment on GotW #5: Overriding Virtual Functions by Mikhail Belyaev
@Barry
Defaults are not inherited. Neither they are stored in virtual tables. So you can not override them, but you can kinda change them in derived classes (and face the judgement). It is a compile-time issue, so it is based on static types.
So afaik d.g() really calls derived::g(20) and pb->g() really calls derived::g(10).
I may be wrong though, don’t have a ready-to-use c++11 compiler now.
Read More »
Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@decourse: It’s not an abstraction leak because it doesn’t affect the caller’s argument. It’s an implementation detail that happens to be visible but isn’t a “leak” inasmuch as it has no effect on the calling code.
@Marshall and Matt: Even in the 1990s, my impression was that talking about writing your code in order to try to enable (N)RVO was overdone; optimizers have been good at this for a long time, some did better with a named temporary and others with an unnamed return value, and debates about whether a named local variable or reusing a parameter or creating a temporary would help the optimizer the most were generally a distraction. In general I think we really do want to teach people to: (a) write code for clarity first (overthinking (N)RVO is usually asking for premature optimization), and (b) pass an input value parameter by value if you’re going to copy from it anyway, because it really does help when passed rvalues. The community seems to be converging on that this is the right advice.
@hm: Thanks, that “explicit” was a leftover from the original 1997-vintage version that no longer applies since I’ve updated the advice (and don’t even talk about explicit conversions any more in the current version). Removed.
@Dave Harris: Thanks, “for” was missing. Added.
Read More »
Delievered to you by Feedamail.
Unsubscribe