前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >现代C++之如何返回一个对象?

现代C++之如何返回一个对象?

作者头像
公众号guangcity
发布2019-12-30 10:13:04
1.2K0
发布2019-12-30 10:13:04
举报
文章被收录于专栏:光城(guangcity)

如何返回一个对象?

一个用来返回的对象,通常应当是可移动构造 / 赋值的,一般也同时是可拷贝构造 / 赋值的。如果这样一个对象同时又可以默认构造,我们就称其为一个半正则(semiregular)的对象。如果可能的话,我们应当尽量让我们的类满足半正则这个要求。

1.返回值优化(拷贝消除)

下面编译的gcc版本是支持c++17的gcc8.3。如果使用gcc5.5等版本结果会不同。

ROV例子1:

代码语言:javascript
复制
#include <iostream>

using namespace std;

// Can copy and move
class A {
public:
    A() { cout << "Create A\n"; }

    ~A() { cout << "Destroy A\n"; }

    A(const A &) { cout << "Copy A\n"; }

    A(A &&) { cout << "Move A\n"; }
};

A getA_unnamed() {
    return A();
}

int main() {
    auto a = getA_unnamed();
}

返回值优化输出:

代码语言:javascript
复制
Create A
Destroy A

禁用返回值优化代码修改(-fno-elide-constructors):

代码语言:javascript
复制
Create A
Destroy A

修改代码如下NROV例子2:

代码语言:javascript
复制
A getA_named()
{
  A a;
  return a;
}

int main()
{
  auto a = getA_named();
}

优化结果同上!

代码语言:javascript
复制
Create A
Destroy A

禁用后的结果:

代码语言:javascript
复制
Create A
Move A
Destroy A
Destroy A

也就是说,返回内容被移动构造了。

示例3:

代码语言:javascript
复制
A getA_duang() {
    A a1;
    A a2;
    if (rand() > 42) {
        return a1;
    }
    else {
        return a2;
    }
}

优化与禁用结果一样:

代码语言:javascript
复制
Create A
Create A
Move A
Destroy A
Destroy A
Destroy A

我们把移动构造删除,得到示例4:

代码语言:javascript
复制
A(A&&)= delete;

此时,前面的move就变成copy。

如果再进一步,把拷贝构造函数也删除呢?得到示例5:

代码语言:javascript
复制
A(const A&&)= delete;
A(A&&)= delete;

是不是上面的 getA_unnamedgetA_named和 getA_duang 都不能工作了?

在 C++14 及之前确实是这样的。但从 C++17 开始,对于类似于 getA_unnamed这样的情况,即使对象不可拷贝、不可移动,这个对象仍然是可以被返回的!C++17 要求对于这种情况,对象必须被直接构造在目标位置上,不经过任何拷贝或移动的步骤。

2.总结

  • copy construct本身在RVO和NRVO两种情况下被优化了,如果再加上move反而画蛇添足。

在 C++11 之前,返回一个本地对象意味着这个对象会被拷贝,除非编译器发现可以做返回值优化(named return value optimization,或 NRVO),能把对象直接构造到调用者的栈上。从 C++11 开始,返回值优化仍可以发生,但在没有返回值优化的情况下,编译器将试图把本地对象移动出去,而不是拷贝出去。这一行为不需要程序员手工用 std::move 进行干预——使用std::move 对于移动行为没有帮助,反而会影响返回值优化。”

  • 加入了move assignment后,默认是调用move assignment而不是copy assignment
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何返回一个对象?
    • 1.返回值优化(拷贝消除)
      • 2.总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档