3

我有一个“构建”要返回的结构的函数:

struct stuff {
    int a;
    double b;
    Foo c;
};
stuff generate_stuff() {
    Foo c = generate_foo();
    //do stuff to Foo, that changes Foo:
    //...
    return {1, 2.0, c};  //should this be return {1, 2.0, move(c)};?
}

我应该c离开这个功能吗?我意识到,(N)RVO 经常可以就地构建对象,但有时可能并非如此。什么时候不能完成 (N)RVO,因此,我应该什么时候移动函数的对象?

换句话说,这显然是返回的临时的 RVO。问题变成了,NRVO(命名返回值优化)会发生c吗?将c在原地构造(在函数的调用点,在临时stuff结构内部),或者将c在函数中构造,然后复制到调用点的结构中。

4

1 回答 1

3

您的调用move(c)不是将 c 移出函数,而是将其移入从函数返回的临时结构中。临时返回值应始终受益于 RVO。但是,我相信 c 到临时的移动/复制不能被优化掉,因为 c 本身不是临时的。因此,这里的移动版本应该始终至少与复制版本一样高效(针对使用 g++、clang++ 和 MVC++ 的简单场景进行了测试)。

如果您必须绝对最小化复制/移动操作的数量,那么您可以编写

struct stuff {
    int a;
    double b;
    Foo c;
};
stuff generate_stuff() {
    stuff s{ 1, 2.0, generate_foo() };
    //use s.c instead of c
    //...
    return s;  
}

由于 NRVO,这将导致仅 Foo 的单个构造并且没有复制/移动。

编辑:正如@dyp 在对您的问题的评论中指出的那样,Stuff 的就地构造实际上并不是 RVO 的情况,而是标准要求的。无论如何,重要的部分是c不能省略的移动/复制,因此使用move永远不会导致性能损失。

于 2015-03-10T00:38:14.047 回答