函数形参类型与返回值类型

参考:

注意,不探讨 const

1. 函数形参

1.1 实参、形参组合

我们知道 c++ 中函数形参可以有如下几种:

  • 左值
  • 左值引用
  • 右值引用

而实参也可以有如下几种:

  • 左值/左值引用
  • 右值

将他们组合起来,形参有如下情况:

  • 形参为左值:
    • 实参为左值/左值引用,那么会发生拷贝构造行为,语义上可以看作资源被复制了一份
    • 实参为右值,那么会发生移动构造行为,语义上可以看作资源发生了转移,caller 不再拥有实参的资源所有权
  • 形参为左值引用:
    • 实参为左值/左值引用,不会发生任何构造行为,语义上可以看作资源被共享了一份
    • 实参为右值,语法错误
  • 形参为右值引用:
    • 实参为左值/左值引用,语法错误
    • 实参为右值,也不会发生任何构造行为,语义上可以看作临时资源被共享了一份。但是实际上,一般右值引用作为形参的函数都是 callee 在函数内部进行移动构造,以转移资源所有权

1.2 智能指针作为形参

智能指针作为形参时,形参类型为左值、右值引用、左值引用都可以。
但是考虑到智能指针是带有引用计数功能的类,从智能指针的设计语义出发,形参为左值引用应该被排除。形参为右值引用意味着 caller 要转移对象资源,由于智能指针类都设计有移动构造(unique_ptr、shared_ptr),所以直接用左值接受即可。
可以参考如下设计规则(https://www.zhihu.com/question/534389744/answer/2500052393):

unique_ptr<widget> factory();              // 生产 widget
void sink(unique_ptr<widget>);             // 消费 widget
void reseat(unique_ptr<widget>&);          // 将或可能修改指针
void thinko(const unique_ptr<widget>&);    // 通常不是你想要的

shared_ptr<widget> factory();              // 确知生产的结果需要共享
void share(shared_ptr<widget>);            // 将保留引用计数
void reseat(shared_ptr<widget>&);          // 将或可能修改指针
void may_share(const shared_ptr<widget>&); // 可能保留引用计数

2. 函数返回值

我们知道 c++ 中函数返回值可以有如下几种:

  • 左值(如果关闭返回值优化特性,实际上对 caller 来说返回的是一个临时对象,一个右值)
  • 左值引用
  • 右值引用

函数返回的值本身,可以看作有如下属性:

  • 非局部对象
  • 局部对象

2.1 返回非局部对象

2.1.1 不转移对象所有权(返回左值或左值引用)

如果返回:

  • 左值,caller 不能采用左值引用进行接收(对于 caller 来说,返回的左值语法上是个临时对象,值属性为右值),触发拷贝构造/赋值构造
  • 左值引用,caller 可以采用左值引用进行接收。也可以采用左值进行接收,触发拷贝构造/赋值构造

2.1.2 转移对象所有权(返回前调用 std::move(),返回形参左值或右值引用)

如果返回:

  • 左值,触发移动构造/移动赋值构造
  • 右值引用,也会触发移动构造/移动赋值构造

2.2 返回局部对象

局部对象返回左值即可,使用左值接收,以触发返回值优化。如果返回引用,无论左值引用还是右值引用,caller 接收对象都是未定义行为

posted @ 2022-02-17 10:04  小夕nike  阅读(279)  评论(0编辑  收藏  举报