简体   繁体   English

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

[英]const reference to temporary and copying - C++

Please consider the following code, 请考虑以下代码,

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;
}

Output on MSVC MSVC上的输出

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

Output of GCC GCC的产出

Constructing!
before return
Destructing..

The result which comes on MSVC looks incorrect. MSVC上的结果看起来不正确。

Questions 问题

  1. AFAIK, GCC produces the correct result here. AFAIK,GCC在这里产生正确的结果。 Why MSVC is giving different results and why it is doing copy construction? 为什么MSVC会给出不同的结果以及它为什么要进行复制构建?
  2. const foo& f = get() and const foo f = get() produces same output because of return value optimization. 由于返回值优化, const foo& f = get()const foo f = get()产生相同的输出。 In this case, which way of writing should be preferred? 在这种情况下,应该首选哪种写作方式?

Any thoughts.. 有什么想法吗..

Your MSVC build has no optimizations on. 您的MSVC构建没有优化。 Turn them on, you'll get identical output for both. 打开它们,你会得到相同的输出。

GCC is merely performing, by default, RVO on your temporary. 默认情况下,GCC仅对您的临时执行RVO。 It's basically doing: 它基本上是这样做的:

const foo& f = foo();

MSVC is not. MSVC不是。 It's making the foo in the function, copying it to the outside the function (ergo the copy-constructor call), destructing the inner foo , then binds the reference. 它在函数中创建foo ,将其复制到函数外部(复制构造函数调用),破坏内部foo ,然后绑定引用。

Both outputs are correct. 两个输出都是正确的。 RVO is one instance where the standard explicitly allows the observable behavior of the program to change. RVO是标准明确允许程序的可观察行为发生变化的一个实例。

You are seeing the return value optimization , which is one kind of copy elision . 您正在看到返回值优化 ,这是一种复制省略 Both programs are correct; 两个程序都是正确的; the compiler is specifically given the option of eliminating a temporary which only serves to move data from one permanent object to another. 编译器专门给出了一个消除临时的选项,该临时仅用于将数据从一个永久对象移动到另一个永久对象。

The get() function is Constructing the local (print Constructing!), and returning a Foo object by value. get()函数是构造本地(print Constructing!),并按值返回Foo对象。 The Foo object being returned must be created and is done so via copy construction (print Copy constructing!). 必须创建返回的Foo对象,并通过复制构造(print copy construct!)完成。 Note that this is the object value assigned to the const foo & f in main. 请注意,这是在main中分配给const foo&f的对象值。

Before that assignment takes place though, the function must return from get() and local variables (ie foo f; in get()) must be destroyed. 在进行该赋值之前,函数必须从get()返回,并且必须销毁局部变量(即foo f;在get()中)。 (print 1st Destructing..) From there the program terminates (ie returns from main) then the object returned by get() and assigned to "f" is destroyed. (print 1st Destructing ..)从那里程序终止(即从main返回)然后get()返回并分配给“f”的对象被销毁。 (print 2nd Destructing...) (打印第二次破坏...)

The reason you're seeing different output for the two compilers is that GCC is optimizing the return value for get() and is simply replacing const foo &f = get() to const foo &f = foo ; 您看到两个编译器的输出不同的原因是GCC正在优化get()的返回值,并且只是将const foo &f = get()替换为const foo &f = foo ;

1) This happens because of different optimization strategy. 1)这是因为不同的优化策略。 Because you don't have operator=, MSVC can restructure code to something like const foo& f(get()) therefore executing copy onstructor. 因为你没有operator =,所以MSVC可以将代码重构为const foo&f(get()),从而执行copy onstructor。 2) Depends on what you want to acheive: 2)取决于你想要实现的目标:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM