为什么在这种情况下调用r值引用构造函数?

时间:2016-08-13 12:58:34

标签: c++ return implicit-conversion

func createFinalStrings() -> [String] {
    let substrings = createSubstrings()
    var finalStrings = [String]()
    let lastChars = substrings.flatMap { $0.characters.last }

    for _ in 0...5 {
        var string = ""
        while string.characters.count < 3 {
            let index = Int(arc4random_uniform(5))
            let lastChar = lastChars[index]
            if string.rangeOfString(String(lastChar)) == nil{
                string = string + String(lastChar)
            }
        }
        finalStrings.append(string)
    }

    return finalStrings
}

我用VC ++ 14.2和GCC 5.4.0测试了代码,两者都输出:

#include<iostream>
using namespace std;

struct B{};

struct A
{
    A(const B &)
    {
        cout<<"A(const B &)"<<endl;
    }
    A(B &&)
    {
        cout<<"A(B &&)"<<endl;
    }
};

A get()
{
    B b;
    return b;
}

int main()
{
    get();
}

为什么输出不是

A(B &&)

此代码与A(const B &) 有任何关系吗? (但A和B是不同的类型,因此copy elision不应该在这里工作)

2 个答案:

答案 0 :(得分:29)

为了响应C ++ 14发布之前的评论,rvalue返回规则发生了变化。这个变化是在过程的后期添加的,并由CWG Issue 1579捕获,修改了12.8 / 32的措辞:

  

return语句中的表达式是(可能带括号的) id-expression ,用于命名具有在正文中声明的自动存储持续时间的对象

这意味着返回任何局部变量现在将该变量指定的对象视为首先是rvalue(如果重载决策失败则再次尝试)。

由于CWG问题被接受为语言中的缺陷,编译器甚至可以在“C ++ 11模式”中实现这一新规则。缺陷的一点是“它始终意味着以这种方式工作”,所以这并不是严格意义上说C ++ 11和C ++ 14之间的变化,而是修改了C ++ 11的含义在2014年。

答案 1 :(得分:5)

复制elision与A相关,而不是在get()堆栈框架中构造。 会发生什么事情是返回的b(因为&#34;因为返回&#34而临时死亡;这是因为C ++ 14),用于构建复制删除主堆栈框架中的A

因为临时对象绑定了你观察到的r值引用。