首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std:移动与编译器优化

std:移动与编译器优化
EN

Stack Overflow用户
提问于 2013-03-25 11:40:27
回答 3查看 1.5K关注 0票数 6

例如:

代码语言:javascript
复制
void f(T&& t); // probably making a copy of t

void g() 
{
    T t;
    // do something with t
    f(std::move(t));
    // probably something else not using "t"
}

在这种情况下,void f(T const& t)是否等效,因为任何好的编译器都会产生相同的代码吗?如果这件事重要的话,我对>= VC10和>= GCC 4.6感兴趣。

编辑:

根据答案,我想详细阐述一下这个问题:

比较rvalue-referencepass-by-value方法,很容易忘记在pass-by-value中使用std::move。编译器仍然可以检查变量是否有更多的更改,并消除不必要的副本吗?

rvalue-reference方法只使优化版本“隐式”,例如f(T()),并要求用户显式指定其他情况,如f(std::move(t)),或者在用户未完成t实例时显式复制f(T(t));。那么,在这种与优化有关的情况下,rvalue-reference方法被认为是好的吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-03-25 11:55:36

肯定不一样了。第一次,T &&只能绑定到rvalue,而T const &可以绑定到rvalue和lvalue。其次,T const &不允许任何移动优化。如果您“可能希望复制t",那么T &&允许您实际复制t,这可能更有效率。

示例:

代码语言:javascript
复制
void foo(std::string const & s) { std::string local(s); /* ... */ }

int main()
{
    std::string a("hello");
    foo(a);
}

在此代码中,包含"hello"的字符串缓冲区必须存在两次,一次在main正文中,另一次在foo正文中。相反,如果使用rvalue引用和std::move(a),则可以“移动”相同的字符串缓冲区,并且只需要一次分配和填充。

正如@Alon所指出的,正确的成语实际上是按值传递

代码语言:javascript
复制
void foo(std::string local) { /* same as above */ }

int main()
{
    std::string a("hello");
    foo(std::move(a));
}
票数 5
EN

Stack Overflow用户

发布于 2013-03-25 11:44:06

嗯,这取决于f对t做了什么,如果它创建了它的副本,那么我甚至会详细地这样做:

代码语言:javascript
复制
void f(T t) // probably making a copy of t
{
    m_newT = std::move(t); // save it to a member or take the resources if it is a c'tor..
}

void g() 
{
    T t;
    // do something with t
    f(std::move(t));
    // probably something else not using "t"
}

然后,允许进行移动c‘’tors优化,在任何情况下都采用t‘资源,如果它被“移动”到了您的函数中,那么您甚至可以获得将它移动到函数的非副本,如果它没有被移动,那么您可能必须有一个副本。

现在,如果在后面的代码中有:

代码语言:javascript
复制
f(T());

然后,在f用户不知道的情况下,自由移动优化。

注意:“在这种情况下,void ( this & t)是否等效,因为任何好的编译器都会产生相同的代码吗?”

它不是等价的,而是较少的工作,因为只有“指针”被转移,没有调用c‘’tors,既不移动,也不调用其他任何东西。

票数 2
EN

Stack Overflow用户

发布于 2013-03-25 13:43:27

接受一个const lvalue引用和一个rvalue引用是两件不同的事情。

相似之处:

  • 两种方法都不会导致复制或移动发生,因为它们都是引用。引用只是引用对象,它不以任何方式复制/移动对象。

差异:

  • const lvalue引用将绑定到任何东西(lvalue或rvalue)。rvalue引用将只绑定到非constrvalue-更有限。
  • 当函数是const lvalue引用时,不能修改函数中的参数。当它是一个rvalue引用时(因为它不是const),它可以被修改。

让我们看一些例子:

  1. const l值参考:void f(const T& t);
代码语言:javascript
复制
1. Passing an lvalue:

T t;f(t);

在这里,t是一个lvalue表达式,因为它是对象的名称。const lvalue引用可以绑定到任何东西,因此t将很高兴地通过引用传递。没有东西被复制,什么都没有被移动。

2.传递价值:

f(T());

在这里,T()是一个rvalue表达式,因为它创建了一个临时对象。同样,const lvalue引用可以绑定到任何东西,所以这是可以的。没有东西被复制,什么都没有被移动。

在这两种情况下,函数中的t都是对传入的对象的引用。它不能被引用修改为const

  1. 参考价值:‘`void (T& t);
代码语言:javascript
复制
1. Passing an lvalue:

T t;f(t);

这将给您一个编译器错误。rvalue引用不会绑定到lvalue。

2.传递价值:

f(T());

这将很好,因为rvalue引用可以绑定到rvalue。函数中的引用t将引用由T()创建的临时对象。

现在让我们考虑一下std::move。首先要做的是:std::move实际上不会移动任何东西。这个想法是,你给它一个lvalue,然后它把它变成一个rvalue。这就是它所能做的。因此,现在,如果您的f接受一个rvalue引用,您可以这样做:

代码语言:javascript
复制
T t;
f(std::move(t));

这是因为,尽管t是一个lvalue,但std::move(t)是一个rvalue。现在,rvalue引用可以绑定到它。

那么,为什么你会采取一个参考价值的论点呢?实际上,除了定义move构造函数和赋值操作符之外,您不应该经常这样做。每当定义接受rvalue引用的函数时,几乎可以肯定地希望给const lvalue引用重载。它们几乎总是成对的:

代码语言:javascript
复制
void f(const T&);
void f(T&&);

为什么这对函数有用?当您给它一个lvalue (或一个const rvalue)时,第一个将被调用,而当您给它一个可修改的rvalue时,将调用第二个rvalue。接收一个rvalue通常意味着您已经得到了一个临时对象,这是个好消息,因为这意味着您可以破坏它的内部,并根据您知道它不会存在很长时间的事实来执行优化。

因此,有了这对函数,您就可以在知道得到一个临时对象时进行优化。

这对函数有一个非常常见的例子:复制和移动构造函数。它们的定义通常如下:

代码语言:javascript
复制
T::T(const T&); // Copy constructor
T::T(T&&); // Move constructor

因此,移动构造函数实际上只是一个副本构造函数,在接收临时对象时对其进行了优化。

当然,传递的对象并不总是临时对象。如上面所示,您可以使用std::move将lvalue转换为rvalue。然后,它似乎是函数的临时对象。使用std::move基本上是说:“我允许您将此对象视为临时对象。”它是否真的被移走是无关紧要的。

但是,除了编写复制构造函数和移动构造函数之外,最好有充分的理由使用这一对函数。如果您正在编写一个函数,它接受一个对象,并且不管它是否是一个临时对象,它的行为都是完全相同的,那么只需使用该对象的值即可!考虑:

代码语言:javascript
复制
void f(T t);

T t;
f(t);
f(T());

在对f的第一次调用中,我们传递一个lvalue。它将被复制到函数中。在对f的第二个调用中,我们传递一个rvalue。该对象将被移动到函数中。瞧-我们甚至不需要使用rvalue引用来高效地移动对象。我们只是按价值拿走了它!为什么?因为用于复制/移动的构造函数是根据表达式是lvalue还是rvalue来选择的。只需让复制/移动构造函数完成他们的工作。

至于不同的参数类型是否会导致相同的代码,这是一个完全不同的问题。编译器在“如果”规则下操作.这就意味着,只要程序按照标准指令运行,编译器就可以发出它喜欢的任何代码。因此,如果函数恰好执行相同的操作,它们可能会发出相同的代码。或者他们可能不会。但是,如果您是接受const值引用和rvalue引用的函数,则这是一个不好的迹象。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15614026

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档