Modernize your C++ code
jarchitect.com
jarchitect.com
I don't get why to make this change and the justification (after following 2 links deep: Want Speed? Pass by Value) is a 404.
Move constructors are great and it's awesome that a bunch of what used to be copy-constructor overuse in C++03 can now be done without deep copies in C++11. But I don't understand why explicitly move from something that is explicit and guaranteed to be cheap (pass by reference) to something that might be cheap if everything has reasonable move-ctors or (if not all ducks are in a row) might simply degrade to incurring the C++03-style over-copies. Does not seem like a strict improvement to me. Seems instead like blindly applying this to existing code will slow it down in some cases, possibly dramatically.
Therefore, "want speed? pass by value" can result in worse performance. Overloading for copy/move is near-optimal and perfect forwarding is optimal - this is what the STL does (push_back is copy/move overloaded, emplace_back perfectly forwards).
I'm guessing this detection is for those cases where the passed-by-ref value is always copied.
That prevents some compiler optimizations ( http://stlab.adobe.com/wiki/images/8/85/2008_06_26_classes_t... ), but those optimizations predate C++11, so I don't know why the advice is in this article. In any case, if you want a function to operate in a copy of a parameter, consider passing that parameter by value instead of passing it by const reference and then making a copy. Note, this is not advice to start making unnecessary copies; instead it's advice that if you need a copy of something, rely on the compiler to make that copy for you.
This illustrates a general principle in software maintenance: later. Push decisions off until they're actually causing problems, and then fix them as soon as it's apparent that they're a problem. Code that's removed because of changing requirements or never touched again because the feature is frozen doesn't need to be maintained. Even for code that does need to be maintained, you have more information about what the optimal architecture for the system is once you built out the system more.
(All this assumes consumer or non-critical enterprise grade software, where the cost of a bug is that you spend time finding & fixing it. If you're doing high-assurance software like avionics or medical devices, or anything where a bug is likely to cause major collateral damage, then by all means add every language feature designed to stop bugs ASAP.)
EDIT: Sorry, mostly rewrote this comment. Apologies if anyone responded during that time.
Sure, but then you're just reacting to bugs. Wouldn't you like to preemptively prevent bugs? I think this is why you might like to use a C++ compiler rather than an interpreter?
Just reacting is sort of like "what you don't know won't kill you". But the thing is that it might end up killing you (figuratively, not as in avionics). Personally, I think it's part of due diligence as a consultant. Anything this will reduce our chances of making an error before runtime is worth it -- up to a point. Does auto-adding "override" exceed the cutoff point? I don't think so.
Btw, how do you know that these potential problems aren't causing (small per day, but large over time) monetary damage? If you have end-to-end metrics, then you're probably fine, but it can be very hard to judge if bugs are actually causing you damage.
(I'm going on a huge assumption here, namely that this tool -- which I'm not familiar with -- is actually semantics-preserving -- which is an extremely hard problem in C++.)
FWIW, the tool is semantics-preserving, and I actually like it (and the general suite of clang refactoring tools) a lot. My point isn't for or against the tool, it's about the general philosophy of maintenance changes. You should use it if you have already decided you're going to switch to C++11, and value style consistency across your team. Or if you are actively having a problem with code maintenance and new features are becoming hard to add - this was the situation that Google was in when we developed the tool. Or because your developers will be happier if they get to use C++11 and don't have to do the conversion work themselves. You should not use it because you read about it on the Internet, or because it's the new hotness.
Hey, reasonable people can disagree! :)
EDIT: "You should not use it because you read about it on the Internet, or because it's the new hotness.". That's a bit of a cheap shot, at least when leveled at the posters in this thread, I think. Hopefully most professional developers are slightly more responsible than that. (Again, experience may differ, so...)
In other words, we suffer from hindsight bias. For any given feature, there is usually some combination of refactorings that will make it easier. The problem is that these refactorings are only evident in hindsight, once we've actually started to write the feature. If you speculatively do the refactoring, it surely will make some features easier to add, but those features are probably not the ones that you actually end up adding.
The way I solve this in my personal programming (where I am both engineer and manager, so my incentives are aligned) is to do any refactorings I wish I had immediately before writing the code. That way, I know exactly what I'm aiming for and exactly what will make it easier, and there's no guesswork involved. Over time, this also seems to produce optimally-compact code, albeit sometimes non-intuitive to someone newly introduced to the project.
Unfortunately, while this seems optimal from a project perspective, it runs counter to the incentives of both the engineers (who want to seem like really fast & reliable coders to management, and not say "This feature will be delayed because of decisions we previously made") and managers (who want to hear "This feature will be delivered tomorrow", and not delayed because of decisions previously made). Solving this incentive mismatch is an open problem; companies with technical management often do better at it but there's still a big information loss here.
I certainly agree that local optimization (as in your response to my "example") usually wins in entrenched situations, but I disagree that it's "hindsight bias". Hindsight bias usually applies when you're responding to a future situation based on previous (idealized!) experience, but if you're already in the middle of a project and deciding what to do, then you're not really in the same situation as if you're starting a new project based on previous experience. (That's a bit mangled, I hope my intention makes sense.)
I'll state plainly that I tentatively buy into the refactor-early-refactor-often mantra, assuming that the language can support that reasonably.
For me, I really think that every situation is "global" vs. "local" optimization thing, and I'll argue towards "global" whenever I can, even if it reduces productivity in the short term. Michael C. Feathers' "Working Effectively with Legacy Code" was very instructive in this regard.
C++11 is nice. For new code. I see no reason to use this for old, working code.
What you get out of it is extra performance — that's it, really.
---
Here's a talk where Google's LLVM team leader introduces both tools: https://www.youtube.com/watch?v=JSjoCisIHcM
The real reason we wanted it was because we had just redesigned the search page entirely [1] and launched Google Instant [2], and the former was launched to "Everything except for IE6 and RTL languages", the latter was launched to "Modern browsers that can handle the performance requirements, if the user has turned it on", and the resulting combination of conditional branches in the code made it virtually impossible to launch anything else. I was leading a short mini-project to get the new interface launched everywhere and clean up all of the dead code paths that had only serviced the old Google interface.
Simultaneously, Chandler and Manuel had come up with this library to do pattern-matching on top of the Clang AST, and they were looking for a reference customer or at least some reason to exist as a project. So they were like "Let us help you with that - we can let you write tools that will fix your 1000+ conditional branches automatically."
Ironically, my project actually failed. (At least the part where we used automated tools to remove dead code - we did succeed in launching the new interface everywhere, so it was considered a success by management). The old code was removed manually by engineers over the next 2 years. But what it did show was that a.) there was demand for these automated refactoring tools inside the company and b.) the primary blocker to effectively writing these tools was the need to reformat source code as you add or remove expressions, which is why clang-format was developed.
[1] http://googleblog.blogspot.com/2010/05/spring-metamorphosis-...
[2] http://googleblog.blogspot.com/2010/09/search-now-faster-tha...
clang-format is actually my favourite out of the two. I never had a real use case for clang-modernize (I did try it once though; just to see the magic happen). clang-format however impresses me pretty much every day. It doesn't really do anything Go's "fmt" command can't do, but it just looks so much more impressive given C++'s complex syntax.
A more charitable explanation that I also consider to be likely is that jbHawk was a long-time HN reader who simply never felt the need to have an account until this post about a pretty neat tool which inspired them to comment.