【问题标题】:Why my object still gets copied when I tried to return a reference为什么当我尝试返回引用时我的对象仍然被复制
【发布时间】:2019-03-19 12:24:54
【问题描述】:
class Obj {
public:
    Obj(int aa, int bb): a(aa), b(bb) {}
    Obj(const Obj& o) {a = o.a; b = o.b;std::cout << "copying" << std::endl;}
    Obj(Obj&& o) {a = o.a; b = o.b;std::cout << "moving" << std::endl;}
    int a;
    int b;
};
const Obj& Min(const Obj &o1, const Obj &o2) {
    if (o1.a > o2.a) {
        return o1;
    } else {
        return o2;
    }
}
int main() {
    using namespace std;

    auto o1 = Obj(1,1);
    auto o2 = Obj(2,2);
    auto res = Min(o1, o2);

    cout << res.a << endl;
    res.a = 100;
    cout << o1.a << endl;
    cout << o2.a << endl;

    return 0;
}

程序仍然会打印一个单词copying,表示复制构造函数已激活。那么构造函数在哪里调用呢?为什么函数没有返回o1的引用,所以修改res的值也会改变o1的值?

【问题讨论】:

  • 尝试auto&amp; res = Min(o1, o2),但不要指望res.a = 100 会起作用,因为您将返回const 参考。
  • 所以这意味着构造是在将Min返回的左引用分配给非引用变量res时实现的?如果我需要使用auto&amp;&amp; res = Min(...) 来获取值怎么办,我该如何做呢?
  • 无论如何,返回一个 const 引用将阻止修改o1
  • 另见decltype(auto),这里的答案都没有提到;这可以在无需编写参考的情况下获得参考,因此如果您编写的代码必须是通用的,那就更好了。 @coincheung 你是什么意思“如果”?你刚写的。但是你有什么理由需要一个右值引用吗?如果您返回对 const 对象成员的引用,您仍然会得到 const 引用。世界上所有的通用代码都无法绕过这一点,这是正确的。

标签: c++ c++11 pass-by-reference auto lvalue


【解决方案1】:

复制在语句中完成:

auto res = Min(o1, o2);

Min() 返回类型为const Obj&amp;。上面的auto 将被推导出为Obj,而不是const Obj&amp;(即res 类型将是Obj)。 res 是一个对象,通过复制构造函数(即Obj::Obj(const Obj&amp;))进行初始化,因此发生了复制构造。

如果你改写:

auto& res = Min(o1, o2)

res 将是 const Obj&amp; 类型,并且不会在那里进行复制构造,因为 res 将是一个引用,而不是一个对象。

【讨论】:

  • 如果您引用了需要这样做的标准部分,则可以加分。
【解决方案2】:

这与auto 推断类型有关:

来自 CPP 工作草案 (N4713):

10.1.7.4.1 占位符类型扣除[dcl.type.auto.deduct]
...
4. 如果占位符是自动类型说明符,则使用模板参数推导规则确定推导的类型 T' 替换 T。

还有:

17.9.2.1 从函数调用中推导出模板参数 [temp.deduct.call]
...
2.如果P不是引用类型:
...
(2.3) — 如果 A 是 cv 限定类型,则忽略 A 类型的顶级 cv 限定符进行类型推导。

  1. 如果 P 是引用类型,则使用 P 引用的类型进行类型推导。

所以下面语句中的 auto

auto res = Min(o1, o2);

res 推导出为Obj,从而在赋值时调用复制构造函数。

所以把上面的修改成这样:

auto& res = Min(o1, o2);

将使autores 推导出为const Obj&amp;

但如果你这样做,res 不能在 main 中修改,因为它是一个 const 参考

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    相关资源
    最近更新 更多