const引用临时和复制 - C ++

时间:2010-03-05 04:50:49

标签: c++ return-value-optimization

请考虑以下代码,

struct foo
{
    foo()
    {
        std::cout << "Constructing!" << std::endl;
    }

    foo(const foo& f)
    {
        std::cout << "Copy constructing!" << std::endl;
    }

    ~foo()
    {
        std::cout << "Destructing.." << std::endl;
    }
};

foo get()
{
    foo f;
    return f;
}

int main()
{
    const foo& f = get();
    std::cout << "before return" << std::endl;
    return 0;
}

MSVC上的输出

Constructing!
Copy constructing!
Destructing..
before return
Destructing..

GCC的输出

Constructing!
before return
Destructing..

MSVC上的结果看起来不正确。

问题

  1. AFAIK,GCC在这里产生正确的结果。为什么MSVC会给出不同的结果以及它为什么要进行复制构建?
  2. 由于返回值优化,
  3. const foo& f = get()const foo f = get()生成相同的输出。在这种情况下,应该首选哪种写作方式?
  4. 任何想法..

4 个答案:

答案 0 :(得分:11)

您的MSVC构建没有优化。打开它们,你会得到相同的输出。

默认情况下,GCC仅对您的临时执行RVO。它基本上是这样做的:

const foo& f = foo();

MSVC不是。它在函数中创建foo,将其复制到函数外部(复制构造函数调用),破坏内部foo,然后绑定引用。

两个输出都是正确的。 RVO是标准明确允许程序的可观察行为发生变化的一个实例。

答案 1 :(得分:1)

您看到了return value optimization,这是copy elision的一种。两个程序都是正确的;编译器专门给出了一个消除临时的选项,该临时仅用于将数据从一个永久对象移动到另一个永久对象。

答案 2 :(得分:1)

get()函数是构造本地(print Constructing!),并按值返回Foo对象。必须创建返回的Foo对象,并通过复制构造(print copy construct!)完成。请注意,这是分配给const foo&amp;的对象值。 f in main。

在进行该赋值之前,函数必须从get()返回,并且必须销毁局部变量(即foo f;在get()中)。 (print 1st Destructing ..)从那里程序终止(即从main返回)然后由get()返回并分配给“f”的对象被销毁。 (打印第二次破坏......)

您看到两个编译器的输出不同的原因是GCC正在优化get()的返回值,只是将const foo &f = get()替换为const foo &f = foo;

答案 3 :(得分:-2)

1)这是因为不同的优化策略。因为你没有operator =,所以MSVC可以将代码重构为const foo&amp; f(get())因此执行copy onstructor。 2)取决于你想要实现的目标:

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.