2

I have been using C++ since 1992 (and reading copious amounts about the language), so I know a fair amount about the language, but far from all. My question is about C++11 named return value optimization - what guarantees are there that it will be performed? I tend to prefer to send in non-const parameters (C++97 style) or use shared_ptr (C++11 style), or even used ptr-to-ptr (C style). One reason is that with non-const ref args or shared_ptr, I am guaranteed that NO extra object copies are made.

So my question is (especially for those C++ programmers who do hard real-time or kernel work): What idioms do you prefer? I REALLY hope this question is not downvoted as imprecise, opinion-based or plain stupid - I know it is highly relevant for efficient, modern C++ programming.

Erik Alapää
  • 2,585
  • 1
  • 14
  • 25
  • 3
    RVO is not a C++11 thing. And C++97 isn't a thing. But RVO has been a part of the language since the standardization (C++98). I prefer returning by value. Less things to think about/document. – juanchopanza Mar 13 '15 at 10:19
  • 2
    Personally, I pass parameters by const reference if they are not to be modified, by pointer if they might be modified (I feel it's clearer to the caller if it's done that way). I tend to return things by value, relying on the compiler to elide copies, or provide a move constructor if I have any concerns that the compiler might not. The only *new* thing here is the move constructor. – Bathsheba Mar 13 '15 at 10:20
  • 1
    There are no hard guarantees, the standard *allows* implementations to perform RVO in certain cases ([class.copy] / 31), but an implementation is free to never use RVO and still be compliant. – user657267 Mar 13 '15 at 10:22
  • 1
    I'd say first rely on it. Trust the compiler, don't try to help it optimize your code. And then measure. IFF you notice that it seems not to optimize with NRVO and that it's a hindrance for you, then move on to a manual solution. – JBL Mar 13 '15 at 10:27
  • @juanchopanza: The standards commitee unanimously approved the C++ standard in Nov 1997, so that is why I called the standard C++97, but probably C++98 is more correct. And for NRVO, as I understand it, it is a C++11 modification of the older rules. – Erik Alapää Mar 13 '15 at 10:28
  • 1
    NRVO certainly pre-dates C++11 and IIRC it was already in C++98. – juanchopanza Mar 13 '15 at 10:38
  • I'm voting to close this question as off-topic because " What idioms do you prefer?" is asking for opinions, and the introduction " I tend to prefer" reinfirces that. NVRO certainly is relevant to C++, and may affect performance, but that doesn't make all NVRO questions on-topic. – MSalters Mar 13 '15 at 10:40
  • 1
    @MSalters: If you do not like serious questions from working programmers about real-life design choices, just read the question and move on to things you like. Voting to close is aggressive and condescending, and should be used to clean out questions and people who are not serious and not sincere, not to demonstrate power at Stackoverflow. – Erik Alapää Mar 13 '15 at 11:41
  • @juanchopanza: At least, there seem to have been changes to the NRVO/RVO rules because of C++11, this is from another question at SO:'Plus, when you return a local variable, it gets moved if it is of a type that has a move constructor, so no copies will be made, period.' – Erik Alapää Mar 13 '15 at 11:52
  • That is incorrect. The quote is either misleading, wrong, or out of context. It is only moved *iff* the copy doesn't get elided. I don't think the NRVO rules have been changed in C++11. – juanchopanza Mar 13 '15 at 15:44
  • Here is the discussion; http://stackoverflow.com/questions/6531700/when-will-a-c11-compiler-make-rvo-and-nrvo-outperform-move-semantics-and-const And it is pretty obvious that such a radical new language feature as rvalue references and move constructors will affect how return value optimization is done, so I think you are wrong on this. But then again, I prefer smart pointers or other mechanisms over RVO/NRVO. – Erik Alapää Mar 13 '15 at 23:08
  • When investigating RVO, I refreshed my knowledge of rvalue references. They are difficult to understand but help writing even faster C++ programs. For example, I like the new std::swap() with rvalue references and std::move. But sometimes things get too hairy for my taste, see e.g. the reference collapsing rules in http://thbecker.net/articles/rvalue_references/section_08.html - things like this make me want to fall back to passing pointers, C-style. – Erik Alapää Mar 16 '15 at 11:04
  • @ErikAlapää reference collapsing is only something you have to worry about when understanding "forwarding references" (whose usefulness outweighs their ugliness). – M.M Jul 24 '15 at 00:10
  • In case you are unaware: so long as your class actually has a move constructor, then the compiler must use it if it decides not to do copy elision. – M.M Jul 24 '15 at 00:34

1 Answers1

2

In Section 12.8/31, the C++11 standard writes

"When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects."

That means your compiler might never use RVO (although most compilers do support it).

Given the above, Scott Meyers' advice from 'Effective Modern C++' (Item 25) is

"Never apply std::move or std::forward to local objects if they would otherwise be eligible for the return value optimization."

The rationale is as follows:

  • If you do apply std::move, then the move constructor (which is more expensive than RVO) will be used, even if RVO was a possibility. So you possibly lose some performance there.
  • If you don't apply std::move, you leave room for RVO should your compiler support it. If your compiler doesn't support RVO, you'll use the move constructor anyway. So you possibly gain some performance there.

Clang will have -Wpessimizing-move and -Wredundant-move warnings for this. See this link.

M.M
  • 138,810
  • 21
  • 208
  • 365