G ++:RVO如何工作的情况下,多个翻译单元参与(g++: How RVO works in ca

2019-09-20 02:07发布

首先请看看下面的代码,其中包含2个翻译单元。

--- foo.h ---

class Foo
{
public:
    Foo();
    Foo(const Foo& rhs);
    void print() const;
private:
    std::string str_;
};

Foo getFoo();

--- foo.cpp ---
#include <iostream>

Foo::Foo() : str_("hello")
{
    std::cout << "Default Ctor" << std::endl;
}

Foo::Foo(const Foo& rhs) : str_(rhs.str_)
{
    std::cout << "Copy Ctor" << std::endl;
}

void Foo:print() const
{
    std::cout << "print [" << str_ << "]" << std:endl;
}

Foo getFoo()
{
    return Foo(); // Expecting RVO
}

--- main.cpp ---
#include "foo.h"

int main()
{
    Foo foo = getFoo();
    foo.print();
}

请确保Foo.cpp中和main.cpp中是不同的翻译单元。 所以按我的理解,我们可以说,存在的getFoo没有实施细则()在翻译单元main.o(main.cpp中)可用。

但是,如果我们编译和执行上面的,我无法看到“复制构造函数”字符串这表明RVO在这里工作。

这将是非常感激,如果有人对你请让我知道该怎么就算“的getFoo()”的实施细则未暴露于翻译单元main.o可以做到这一点?

我通过使用GCC(克++)4.4.6进行上述实验。

Answer 1:

编译器只是有工作始终。

换句话说,编译器必须在返回类型单独看,并基于该类型,决定如何返回该类型的对象的函数将返回值。

至少在一般情况下,这个决定是相当微不足道。 它留出寄存器(或可能是两个)用于返回值(例如,在Intel / AMD的x86 / x64的那会通常是EAX或RAX)。 任何类型的足够小,以适应将要返回那里。 对于任何类型的太大,不适合在那里,该函数将接收告诉它在哪里存放返回结果的隐藏指针/引用参数。 请注意,这多不适用RVO / NRVO被卷入的话-事实上,它同样适用于C代码,返回一个struct ,它确实给C ++返回一个class的对象。 虽然返回一个struct用C可能是不太一样共同的象在C ++中,它仍然允许的,编译器必须能够编译代码,不会吧。

有真的可以消除两个独立的(可能的)副本。 一个是编译器可以在栈上分配空间的局部保持会是怎样的返回值,然后从那里复制到返回时的指针指向。

二是从返回地址可能复制到一些其他地方,价值真正需要的结束。

第一个被淘汰的功能本身里面,而是有其外部接口上没有影响。 它最终使地方隐藏的指针告诉它的数据 - 唯一的问题是它是否首先创建一个本地副本,或者总是直接返回点工作。 显然,用[N] RVO,它总是直接运行。

第二个可能的副本是从(潜在的)临时到哪里的价值真正需要的结束。 这是通过优化调用序列消除,而不是函数本身 - 即给函数的指针最终目的地为返回值,而不是一些临时位置,从该编译器会那么该值复制到它的目的地。



Answer 2:

main并不需要实施细则getFoo的RVO发生。 它只是预期的返回值是在经过一番寄存器getFoo退出。

getFoo有这两个选择-创造在其范围内的对象,然后复制(或移动)到返回寄存器,或直接在寄存器中创建对象 。 这是发生了什么。

这不是告诉主看别的地方,也不需要。 它只是直接使用返回寄存器。



Answer 3:

(N)是RVO无关的翻译单元。 该术语通常用于指的是可应用的一个功能内(从一个局部变量来返回值),并通过呼叫方(从返回值到本地变量)两个不同的副本省音,并且它们应讨论分别。

附近RVO

这是一个函数内部严格履行,可以考虑:

T foo() {
   T local;
   // operate on local
   return local;
}

从概念上有两个对象, local和返回的对象。 编译器可以在本地分析功能,并确定两个对象的生命周期势必: local只活作为副本的返回值的源。 然后,编译器可以在单个可变结合两个变量,并使用它。

在发送方复制省略

在主叫侧,考虑T x = foo(); 。 再次存在两个对象,返回的对象从foo()x 。 又一次的编译器可以判断寿命绑定,并放置在同一位置的两个对象。

进一步阅读:

  • 值语义:NRVO

  • 值语义:复制省略



文章来源: g++: How RVO works in case that multiple translation units are involved
标签: c++ g++ rvo