Forwarding of return values. Is std::forward is needed?

后端 未结 3 1417
予麋鹿
予麋鹿 2021-02-03 21:00

I am writing library which wraps a lot of functions and methods from other library. To avoid coping of return values I am applying std::forward like so:

         


        
相关标签:
3条回答
  • 2021-02-03 21:47

    No you dont need to use std::forward better dont return r-value reference at all because it can prevent of NRVO optimization. You can read more about move semantics in this article: Article

    0 讨论(0)
  • 2021-02-03 21:55

    In the case that you do know that t will not be in a moved-from state after the call to f, your two somewhat sensible options are:

    • return std::forward<T>(t) with type T&&, which avoids any construction but allows for writing e.g. auto&& ref = wrapper(42);, which leaves ref a dangling reference

    • return std::forward<T>(t) with type T, which at worst requests a move construction when the parameter is an rvalue -- this avoids the above problem for prvalues but potentially steals from xvalues

    In all cases you need std::forward. Copy elision is not considered because t is always a reference.

    0 讨论(0)
  • 2021-02-03 21:55

    Depending on what this function gets passed, it results in undefined behavior! More precisely, if you pass a non-lvalue, i.e. an rvalue, to this function, the value referenced by the returned reference will be stale.

    Also T&& isn't a "universal reference" although the effect is somewhat like a universal reference in that T can be deduced as T& or T const&. The problematic case is when it gets deduced as T: the arguments get passed in as temporary and die after the function returns but before anything can get hold of a reference to it.

    The use of std::forward<T>(x) is limited to, well, forwarding objects when calling another function: what came in as a temporary looks like an lvalue within the function. Using std::forward<T>(x) lets x look like a temporary if it came in as one - and, thus, allow moving from x when creating the argument of the called function.

    When you return an object from a function there are a few scenarios you might want to take care of but none of them involves std::forward():

    • If the type is actually a reference, either const or non-const, you don't want to do anything with the object and just return the reference.
    • If all return statements use the same variable or all are using a temporary, copy/move elision can be used and will be used on decent compilers. Since the copy/move elision is an optimization, it doesn't necessarily happen, however.
    • If always the same local variable or a temporary is returned it can be moved from if there is a move constructor, otherwise the object will be copied.
    • When different variables are returned or when the return involves an expression, references may still be returned but copy/move elision will not work, nor will it be directly possible to move from the result if isn't a temporary. In these cases you need to use std::move() to allow moving from the local object.

    In most of these cases the produced type is T and you should return T rather than T&&. If T is an lvalue type the result may not be an lvalue type, though, and it may be necessary to remove the reference qualification from the return type. In the scenario you specifically asked about the type T works.

    0 讨论(0)
提交回复
热议问题