Link or Refund - Best Practice

For example, we have a coding function. What is the best to use:

void Crypto::encoding(string &input, string &output) { //encoding string output = encoded_string; } 

or

 string Crypto::encoding(string &input) { //encoding string return encoded_string; } 

Should we use a link or return to return a string? As far as I know, it will take some time to return a string in order to initialize a new string, which will be returned by return. When I work on a reference variable, I do not waste time initializing some new variable. I just end the function.

Should we mainly use reference and make function return type void? Or do we need to return data only by reference, when we want to return two or more variables, and when we need to return one variable, then use the return command?

+6
source share
7 answers

Do not optimize what you did not measure.

It is usually better (more readable) to return the result of your calculation with return . If this takes a long time because the object is too thick, you can still return to returning the result through the reference parameters, but only after you have proved that this will lead to a significant increase in performance (measure it). For example, if you only ever code very short strings and only do it from time to time, the overhead of copying is negligible.

+9
source

Copying things is usually eliminated, since most modern compilers have RVO functions. You can take advantage even without C ++ 11.

+6
source

If your compiler supports the C ++ 11 standard and r-value links , then returning the value of std :: string is actually quite effective. Prior to this function, the answers could have been slightly different, since you relied only on a compiler that ran RVO .

I would say that using the return value is probably more natural, and also means that you can assign the result to a constant local variable or to a member of the class to avoid accidental modification, for example.

 const std::string result = crypo.encoding("blah"); 

or

 class SomeClass { public: Someclass(Crypto& crypto, const std::string& input) : m_output(crypo.encoding(input)) { } private: const std::string m_output; }; 

Just make sure you are not returning a const value, as this will interfere with the semantics of movement.

+2
source

I use links. This allows the developer to make and abstract the choice without risking the client (in some cases this is important, and some will not).

I also use them for a consistent style - I don’t like viewing public interfaces, which are passed on the details of their implementation.

Transients and copies can be expensive - they vary greatly in the type that you pass. Return by value means that the type must be trivially constructive, with the possibility of replacement, with the ability to copy, move. The compiler can do some great optimizations in this area (RVO / move), but you can also make informed decisions to minimize the costly operations in your implementations. When you no longer use types, everyone knows the characteristics of copying, and choosing the return method becomes very difficult, so I just keep it simple and prefer links.

Passing a link has several other advantages, for example, when the client prefers to use a subclass of the passed type.

Another advantage if you need an optimized program: I often delete a copy of ctor and operator= if they are not trivial or possible. Passing using a mutable reference allows you to work with types that are not copied / assigned.

In the strict sense of std::string , used in this question: returning the value of std::string by value is quite common, and for this case, many optimizations have been made - RVO, COW and moves - some well-known. As Voo points out in the comments below, returning by value is often easier to read. In the case of std::string and higher level programs, returning by value is unlikely to be a problem, but it is important to measure it in order to understand the costs associated with standard library implementations that you use if performance is important (which may be the case).

An important consideration is that if you are trying to improve an existing program, make sure that you understand how the implementation is performed and find out how to use types most efficiently when performance is important. Implementations can be written and optimized for actual use, which means that they can be pessimistic and in some cases guessing about you, and your attempts to improve performance may already be realized or unconventional use of this type may degrade performance. The typical resizing behavior of a std::vector is a good example. Using a high-performance road adds a lot of time and complexity to what you need to know in order to achieve the best results, and this obviously depends on the implementations you use, as well as the types you use. If productivity is critical and worth the non-trivial investment of time, learning about the types that you use is worthwhile, which can lead to significant success.

I should also add that I often work at low levels - where productivity is critical and / or resources are limited. There can be many restrictions, including exceptions, no locks (heap allocation is also not implied), minimal abstraction costs, and even limited use of dynamic polymorphism. It can be considered quite demanding, even for C ++. I choose the link for the main low-level components, but I will relax this rule if I know that the program will be used only in higher-level domains or unit tests.

+2
source

With the new C ++ 11 standard, you can use the second option due to the new move semantics.

Most likely, your compiler still only supports the old standard. In this case, your first example does not cause any copying, and better.

+1
source

I will record as they say: probably not one.

Your encode looks to me very similar to the fact that it can / should be a universal algorithm that should really use iterators, and not directly handle strings.

 template <class InputIterator, class OutputIterator> void encode(InputIterator begin, InputIterator end, OutputIterator result) { while (begin!=end) *result++ = encode_byte(*begin++); } 

Thus, you can (for example) easily reuse the exact same code to encode data directly from the input stream (via std::istream_iterator ) to the output stream (via std::ostream_iterator ).

It also usually resolves most of the performance questions.

+1
source

I like the second version better because it looks more like a math function. If you are only returning a string, you should have good performance.

+1
source

Source: https://habr.com/ru/post/901349/


All Articles