复制省略:在 return 语句中使用三元表达式时未调用移动构造函数?

2024-01-17

考虑以下示例:

#include <cstdio>

class object
{
public:
    object()
    {
        printf("constructor\n");
    }

    object(const object &)
    {
        printf("copy constructor\n");
    }

    object(object &&)
    {
        printf("move constructor\n");
    }
};

static object create_object()
{
    object a;
    object b;

    volatile int i = 1;

// With #if 0, object's copy constructor is called; otherwise, its move constructor.
#if 0
    if (i)
        return b; // moves because of the copy elision rules
    else
        return a; // moves because of the copy elision rules
#else
    // Seems equivalent to the above, but behaves differently.
    return i ? b : a; // copies (with g++ 4.7)
#endif
}

int main()
{
    auto data(create_object());

    return 0;
}

请考虑 C++11 工作草案 n3337.pdf, 12.8 [class.copy], 第 32 点中的这一点:

当满足或将满足复制操作省略的条件时,除了源对象是函数参数这一事实之外,并且要复制的对象由左值指定,首先执行重载决策以选择复制的构造函数,就像该对象由右值指定一样。如果重载决策失败,或者所选构造函数的第一个参数的类型不是对象类型的右值引用(可能是 cv 限定的),则将再次执行重载决策,并将该对象视为左值。 [注意:无论是否发生复制省略,都必须执行此两阶段重载决策。如果不执行省略,它确定要调用的构造函数,并且即使省略调用,所选构造函数也必须可访问。 ——尾注]

因此,如果我们使用#if 1在该示例中,返回对象时首先尝试移动构造函数,然后尝试复制构造函数。由于我们有一个移动构造函数,因此使用它来代替复制构造函数。

在最后return中的声明create_object()但是,我们发现没有使用移动构造函数。这是否违反了语言规则?该语言是否要求最后使用移动构造函数return陈述?


条件运算符的规范非常复杂,令人恐惧。但我相信你的编译器的行为是正确的。参见 5.16 [expr.cond]/p4:

如果第二个和第三个操作数是相同值的泛左值 类别并且具有相同的类型,结果就是该类型和值 类别 ...

另请参阅 12.8 [class.copy], p31, b1,其中描述了何时允许复制省略:

in a return具有类返回类型的函数中的语句,当 表达式是非易失性自动对象的名称(其他 比函数或 catch 子句参数)具有相同的 cv- 非限定类型作为函数返回类型,复制/移动操作 可以省略...

该表达式不是自动对象的名称,而是条件表达式(并且该条件表达式是左值)。所以这里不允许复制省略,也没有什么其他说明左值表达式可以假装是重载决策的右值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

复制省略:在 return 语句中使用三元表达式时未调用移动构造函数? 的相关文章

随机推荐