8

C++函数传参的时候,右引(T&&)和常引(const T&)接收的参数有什么不同...

 3 years ago
source link: https://www.zhihu.com/question/437590377/answer/1658224380
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
C++函数传参的时候,右引(T&&)和常引(const T&)接收的参数有什么不同,分别该什么时候用?
登录一下,更多精彩内容等你发现
贡献精彩回答,参与评论互动
C++程序猿, 公众号:高级开发者

就我经验来说一下关于函数参数传参,什么时候用T&&,什么时候用const T&

首先回答几个问题,为什么不用值而是用引用?因为传引用可以减少多余的拷贝,提高运行时效率;为什么不用指针而是用引用?因为在防御式编程中指针传递过程中需要层层判空。

达成共识后,引用常用的就三种:T&, const T&, T&&,其中后两种可以传临时变量(右值),而第一种只能传递左值。

倘若实现一个函数,怎么让这个函数更加好用呢?请看如下代码:

///////////////////////////////////////////////////////////////////////////////
// T&
Result f(Value& v) { /* ... */ }

// usage
Value v;
auto res = f(v);

///////////////////////////////////////////////////////////////////////////////
// const T&
Result f(const Value& v) { /* ... */  }

// usage
auto res = f(Value{});

///////////////////////////////////////////////////////////////////////////////
// T&&
Result f(Value&& v) { /* ... */  }
auto res = f(Value{});

可以看到后两种方式能够让客户少写一行值的定义,传参的时候直接创建临时变量(也许来自于其他函数的返回值,而不是直接构造),同样实现的功能,后两种使用起来比第一种更加友好。

T&&相较于const T&多了一个能力,就是 修改右值的能力,比如我这个函数需要定义状态,而又不想让客户来定义传递,那么通过函数参数的默认值(也是右值)做到,例如我写的这个全排序函数:

int numberOfPermutation(int N, vector<int>&& visited = {}) {
    if (visited.size() == N) {
        for (int i = 0; i < N; ++i) printf("%d ", visited[i]);
        puts("");
        return 1;
    }
    int count = 0;
    for (int j = 0; j < N; ++j) {
        if (std::find(visited.begin(), visited.end(), j) == visited.end()) {
            visited.push_back(j);
            count += numberOfPermutation(N, 
                       std::forward<decltype(visited)>(visited));
            visited.pop_back();
        }
    }
    return count;
}

// usage
int res = numberOfPermutation(4);
printf("res = %d\n", res);

注意函数递归传visited参数的时候,既可以用std::move(visited)也可以用std::forward<decltype(visited)>(visited),虽然两者背后一样都是static_cast<_T&&>(__t),但是表达语义不一样:仅仅转发参数而不是移动参数

注意我举的例子T都是具体类型,而不是模板参数那个T,模板参数的T&&语义有很大的不同,这里不展开了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK