移动语义和完美的转发差异 [英] Move semantics and perfect forwarding difference

查看:190
本文介绍了移动语义和完美的转发差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经得到了什么移动语义是从这个问题:
什么是移动语义? / a>

I already got what move semantics is from this question: What are move semantics?

但是我还是没有得到什么完美的转发与移动语义相关。

But I still do not get what perfect forwarding is in relation to move semantics.

推荐答案

纯粹的英语尝试



问题可能太复杂,不能用简单的英语句子来准确描述,但是人们可以认为完美转发是一种将传递给函数的临时值移动到另一个函数的方法。如果第一个函数根本不存在,因此没有任何不必要的副本或分配。 C ++ 11允许你通过在r-value(&& amp;)和l-value(&)引用之间引入一些转换规则来尝试获取引用(r值或l -value)。

Plain English-only attempt

The problem is probably too complex to be accurately described by plain English sentences, but one could think of perfect forwarding as a way to move temporary values passed to a function to another one as if the first function didn't exist at all, so without any unnecessary copies or assignments. C++11 allows you to do this by introducing some conversion rules between r-value (&&) and l-value (&) references to a type when you try to get a reference (either r-value or l-value) out of them.

R值引用是C ++ 11的一个特性,它们被设计为同时处理移动语义和完美转发问题

R-value references are a feature of C++11 and they were designed to both address move semantics and perfect forwarding issues

这是简单的英语解释,但如果您想彻底了解问题,建议您阅读以下内容:

This is the plain-English explanation but if you want to thoroughly understand the problem, I'd suggest reading the following:

我们需要一些临时值传递给函数 F 将传递给另一个 E (不含任何副本或作业)。

We want some temporary values passed to a function F to be passed to another one E without any copy or assignment.


  • 如果您尝试通过引用传递

  • If you try to pass it by reference like

template<typename T> void F(T& a) { E(a); }

您将无法使用临时值(它们不是l值)

you will not be able to use temporaries (they're not l-values)

F(1, 2, 3); // Won't work


  • 声明引用 const 延长堆栈中临时的生命周期(这在历史上是为了避免常见的悬挂引用错误),所以以下工作

  • Declaring a reference as const prolongs the lifetime of a temporary on the stack (this was historically done to avoid a common dangling reference error) so the following works

    template<typename T> void E(const T& a) {}
    
    template<typename T> void F(const T& a) {
        E(a);
    }
    

    但是缺点是你必须修改函数的签名

    but the downside is that you'll have to modify the signature of the function(s) to conform to this solution

    如果我们对E的签名感兴趣(它应该符合某些东西),而不是F的签名可能会消失

    If we're interested in the signature of E (it should conform to something) but not in F's one, we might get away with

    template<typename T> void E(T& a) {}
    
    template<typename T> void F(const T& a) {
        E(const_cast<T&>(a));
    }
    

    但是如果调用 real const

    不可维护的解决方案可以定义所有的变体需要

    An unmaintainable solution could be to define all the variants you need

    template<typename T> void E(T& a) {}
    
    template<typename T> void F(T& a) { E(a); }
    template<typename T> void F(const T& a) { E(const_cast<T&>(a)); }
    

    ,但随着参数数量的增加,组合数量也会增加: this很可能无法维护

    but as the number of parameters grow, the number of combinations grows as well: this is likely to become unmaintainable

    C ++ 11定义了一些规则,规定了

    C++11 defines some rules that state


    到类型T,尝试
    创建类型对于cv TR的左值引用创建类型lvalue
    对T的引用,而尝试创建类型rvalue引用
    在人形式(TR =对类型T的引用,R =引用)中创建类型TR。

    "[given] a type TR that is a reference to a type T, an attempt to create the type "lvalue reference to cv TR" creates the type "lvalue reference to T", while an attempt to create the type "rvalue reference to cv TR" creates the type TR."



    < :

    in human-form (TR = a reference to type T, R = reference):

    TR      R
    T& & -> T&    // an lvalue reference to cv TR (becomes)-> lvalue reference to T 
    T& && -> T&   // an rvalue reference to cv TR (becomes)-> TR (lvalue reference to T) 
    T&& & -> T&   // an lvalue reference to cv TR (becomes)-> lvalue reference to T 
    T&& && -> T&& // an rvalue reference to cv TR (becomes)-> TR (rvalue reference to T)
    

    这里的重要的是,所接收函数的类型:您可以接收l值并将相同的l值传递给E,或者您可以接收r值并传递相同的r值(在转换之后,到E:

    The important takeaway here is that now you can keep track of the type the function received: you can receive an l-value and pass the same l-value to E or you can receive an r-value and pass the same r-value (after converting it since an l-value reference to whatever type reference becomes an l-value reference) to E:

    template<typename T> void E(T&& a) {}
    
    template<typename T> void F(T&& a) { E(static_cast<T&&>(a)); }
    

    static_cast<T&&>(a)
    



    is

    std::forward<T>(a); // is the same as static_cast<T&&>(a);
    

    因此,解决问题并使您的生活更轻松的最终代码是

    so the final code that solves the problem and makes your life easier is

    template<typename T> void E(T&& a) {}
    
    template<typename T> void F(T&& a) { E(std::forward<T>(a)); }
    

    Live example < a>

    Live example

    参考文献:Herb Sutter的博客和其他一些资料,不幸的是我找不到了。如果任何人有一个线索,那些请写在他们下面的评论,我会更新的职位。谢谢。

    References: Herb Sutter's blog and some other sources which unfortunately I can't find anymore. If anyone has a clue about those please write them in the comments below and I'll update the post. Thanks.

    这篇关于移动语义和完美的转发差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆