【问题标题】:Defining a variable that is either an existing value or a new one in C++在 C++ 中定义一个既可以是现有值也可以是新值的变量
【发布时间】:2021-07-21 17:40:06
【问题描述】:

我可以使下面的代码在不复制对象 b 的情况下工作吗?

#include <iostream>
using namespace std;
class A{
        public:
                A() = default;
                A(const A& a) { cout << "copy ctor\n"; }
                A(A&& a) { cout << "move ctor\n"; }
                A& operator=(const A& a) { cout << "copy\n"; return *this;}
                A& operator=(A&& a) { cout << "move\n";  return *this;}
};

A Gen() {
        A x;
        return x;
}

int main() {
        bool cached = true;
        const A b;
        const A& a = cached ? b : Gen();
}

似乎当cached 为真时,就会调用复制ctor。

*编辑:在实际代码中,A类有点大,所以我想避免复制。 *编辑 2:我将 b 设为常量,以阐明意图。

【问题讨论】:

  • 我可以想办法做到这一点,这样当cached 为假时,只会调用移动构造函数。
  • @SamVarshavchik 怎么样?
  • 这能回答你的问题吗?
  • @SamVarshavchik 是的,有问题的部分是当cached 变为真时b 被复制。

标签: c++


【解决方案1】:

条件运算符的整体类型不是引用类型,因为“false”分支不是引用。因此,即使在“真”分支中,也必须复制b 对象,以匹配Gen() 调用的类型。该赋值引用了该复制的对象。

在您的情况下,您可以通过简单地将 Gen() 在“false”分支中返回的对象转换为对该对象的引用来避免此复制操作:

const A& a = cached ? b : static_cast<const A&>(Gen());

请注意,这个转换是在您的原始代码中(隐式地)由赋值运算符执行的(如果 cached 是 false 将创建对返回对象的引用)。

【讨论】:

    【解决方案2】:

    当使用三元运算符时,b 被处理为 glvalue。这将导致复制构造函数调用。如果您想避免这种情况,请写 std::move(b),它为您提供 rvalue 参考。在这种情况下,将调用移动构造函数。

    更多信息可以在here找到。

    【讨论】:

    • 但这会改变b的值,不是吗?
    • @wk_j: std::move 只是一个演员表,所以自己没有修改。
    • @Jarod42 我的意思是,最终调用了一个移动构造函数,因此对象b 发生了变化。哦,再想一想,我应该用b 作为常量发布问题。
    • @wk_j:避免以使现有答案无效的方式修改您的问题。这里,随着移动,你从std::move(b)得到const A&amp;&amp;,从Gen()得到A,通用类型应该是const A,这样就可以复制了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2014-05-28
    • 1970-01-01
    相关资源
    最近更新 更多