当前位置: 首页 > 知识库问答 >
问题:

为什么C++不知道在初始值列表中使用变量时在返回中进行隐式移动?

孟英锐
2023-03-14

请考虑以下代码:

#include <iostream>
template<typename A>
struct S{
    S(const A& a){
        std::cout << "L\n";
    }
    S(A&& a){
        std::cout << "R\n";
    }
};
S<int> f1(){
    int a = 1;
    return {a};
}
S<int> f2(){
    int a = 1;
    return a;
}
S<int> f3(){
    int a = 1;
    return {std::move(a)};
}
int main()
{
    f1();
    f2();
    f3();
}

输出为

L
R
R

您可能知道,C++在返回中隐式移动(f2中)。当我们在初始值列表中手动执行时,它可以工作(f3),但在F1中它不是由C++自动执行的。

这是否有一个很好的理由不起作用,还是仅仅是一个被认为不够重要的角落案例,而不是标准所规定的?

附注。我知道编译器可以(有时必须)执行RVO,但我不明白这如何解释输出。

共有1个答案

伯英锐
2023-03-14

好在:

return name;

这是一个很简单的例子:很明显,你返回的只是一个对象,名字,这里没有其他的把戏。然而,这种特殊情况导致了一个又一个补丁。所以,也许终究没那么简单。

一旦我们在此基础上加入任何更多的复杂性,它就会变得更加复杂。

返回初始值列表后,我们必须开始考虑各种其他情况:

// obviously can't move
return {name, name};       

// 'name' might refer to an automatic storage variable, but
// what if 'other_name' is an alias to it? What if 'other_name'
// is a separate automatic storage variable but is somehow
// dependent on 'name' in a way that matters?
return {name, other_name}; 

你只是...不能知道。我们可以考虑的唯一情况是由单个名称组成的初始值列表:

return {name};

那件事也许可以含蓄地移开。但问题是,在这种情况下,你可以移动:

return {std::move(name)};

对于返回name;的具体问题是,返回std::move(name);有时是强制性的,有时是悲观的,我们希望您始终只编写一个内容,并获得最佳行为。这里没有这种担心,return{std::move(name)};不能以同样的方式禁止复制删除。所以写这些就不是什么问题了。

 类似资料:
  • 问题内容: 我正在努力理解为什么我在使用Swift的iOS项目中遇到此编译器错误。如果我创建以下类: 我在“初始化前使用了变量’self.c’” 这一行上收到编译器错误。 起初我以为这是因为编译器无法验证该方法是否无法访问,但是后来我尝试将init方法混入一点: 这次的错误是“在初始化之前使用了变量’self.b’”(在同一行上)。这表明编译器 是 能够检查其性能的方法访问,所以据我可以看到应该有

  • 我已经检查过自己,我写了一个这样的程序 我运行了几次程序,结果始终是一样的,零。我在C中尝试过,结果是一样的。 但我的教科书说 如果未初始化函数内定义的变量,则该变量值将保持未定义状态。这意味着该元素具有以前驻留在内存中该位置的任何值。 当程序始终将可用内存位置分配给变量时,这怎么可能?它怎么可能是零以外的东西(我假设默认的可用内存值为零)?

  • 问题内容: 我想知道静态变量(在类中)何时出现在图片中(初始化)?是在实例构造函数首次调用之后还是在类加载之后?什么时候加载类? 问题答案: 哦,那很复杂。这取决于是否设置了标志,而标志(在C#中)又取决于是否有静态构造函数。更糟的是;在.NET 4中, 我相信 行为发生了变化,使其比以前更加“懒惰”。 坦白说,我不会在此处编写任何特定行为的代码。简单:只要您使用常规代码访问静态字段,它们就会在尝

  • 问题内容: 我有一个简单的Java类,如下所示: 这段代码的输出是这样的: 为什么s不在finally块中覆盖,而是控制打印输出? 问题答案: 在与所述的执行块完成语句和的值在时间语句执行是由该方法返回的值。finally子句稍后s(在语句完成之后)更改值的事实(此时)并未更改返回值。 请注意,以上内容处理的s是对块中自身值的更改,而不是对s引用对象的更改。如果s是对可变对象的引用(String不

  • 问题内容: Java的设计者是否有任何理由认为不应为局部变量提供默认值?认真地讲,如果实例变量可以被赋予默认值,那为什么我们不能对局部变量做同样的事情呢? 问题答案: 声明局部变量主要是为了进行一些计算。因此,程序员决定设置变量的值,并且不应采用默认值。如果程序员错误地没有初始化局部变量并且使用默认值,则输出可能是一些意外值。因此,在使用局部变量的情况下,编译器将要求程序员在访问变量之前使用一些值

  • 问题内容: 我正在尝试用Python做某事,但我陷入了困境。我在Couchdb中有一个用户列表(使用python benchdb库和Flask框架),这些用户具有用户名(即_id)和电子邮件。我想在jinja2模板的选择框中使用电子邮件地址列表。 我的第一个问题是如何访问电子邮件地址。如果我做: 我得到: 这样我就可以获得我的电子邮件列表。但是我残酷的经验不足之处在于我不知道该如何使用它们。该列表