I disagree with the sentence "I believe that it is better not to rely on optimizing the compiler to make your code efficient." This is basically a compiler for the whole job. Your task is to write clear, correct, and supported source code. For every performance issue that I have ever had to fix, I had to fix a hundred or more problems caused by the fact that the developer tried to be smart, and not to do something simple, correct and maintained.
Let's look at some of the things you could do to try to βhelpβ the compiler and see how they affect the maintainability of the source code.
- You can return the data via the link
For example:
void hello(std::string& outString)
Returning data using a link makes the code on the call node hard to read. It is almost impossible to say which function causes the mutate state as a side effect and which are not. Even if you are really careful with the constant qualifying links that are difficult to read on the call site. Consider the following example:
void hello(std::string& outString);
Even greeting greetings is unclear. Did he change outString, or did the author just messy and forget that const matches the link? Functional style code is easier to read, understand, and complicate in order to break accidentally.
Avoid
- You can return a pointer to an object, rather than returning an object.
Returning the pointer to the object makes it difficult to verify the correctness of the code. If you are not using unique_ptr, you must trust that someone using your method is solid and will definitely delete the pointer when it is done with it, but that is not very RAII . std :: string is already a RAII wrapper type for char *, which abstracts the life problems associated with returning a pointer. Returning the pointer to std :: string simply repeats the problems that were designed to solve std :: string. Relying on a person to be diligent and carefully read the documentation for your function and know when to delete the pointer and when not to delete the pointer is unlikely to have a positive result.
Avoid
- This leads us to move the constructors.
The move designer simply transfers ownership of the data specified in the βresultβ to the final destination. Subsequently, access to the "result" object is invalid, but it does not matter - your method has ended, and the "result" object has gone out of scope. No copy, just transferring ownership of the pointer with clear semantics.
Typically, the compiler will call the move constructor for you. If you are really paranoid (or know that the compiler will not help you), you can use std :: move .
Do it if at all possible.
Finally, modern compilers are astounding. With the modern C ++ compiler, in 99% of cases, the compiler is going to do some kind of optimization to eliminate the copy. The other 1% of the time will probably not matter for performance. In special cases, the compiler can rewrite a method like std :: string GetString (); void GetString (std :: string & outVar); automatically. The code is still easy to read, but in the final build you get all the real or imaginary advantages in speed of returning by reference. Do not sacrifice readability and maintainability for performance unless you have specific knowledge that the solution does not meet your business requirements.