C++学习 (函数引用传参--返回两个结果)

该程序演示了一个C++函数,用于检查给定字符串内是否存在特定字符,并返回其出现次数和首次出现的位置。在示例中,字符'e'在字符串'qweeweeee'中首次出现在第三个位置,共出现了6次。

给定一个字符串,查看字符串内是否有想要的字符,并返回出现次数和出现该字符的位置

#include<iostream>
#include<string>
using namespace std;

//当无需修改引用形参的值时,最好使用常量引用(const)

//给定一个字符串,查看字符串内是否有想要的字符,并返回出现次数
string::size_type counts(const string &s, char c, string::size_type &occurs_num)  // 如果不是引用传参的话,occurs_num变量会在函数结束销毁
{
    //传入occurs_num参数 可以让函数同时返回两个结果
    occurs_num = 0;
    string::size_type occurs_location = s.size();
    //遍历字符串内的每个字符 判断是否与c相同
    for (decltype(occurs_location) i = 0; i != s.size(); i++)
    {
        if (s[i] == c)
        {
            if (occurs_location == s.size())
            {
                occurs_location = i + 1;
            }
            ++occurs_num;
        }
    }

    return occurs_location;

}
int main()
{
    string::size_type ctr = 0;
    string s = "qweeweeee";
    auto index = counts(s, 'e', ctr);
    cout << "字符'e'第一次出现在第" << index << "个位置" << endl << "出现的次数是" << ctr << endl;
    return 0;
}

运行结果如下:

字符'e'第一次出现在第3个位置
出现的次数是6

<think>我们正在讨论C++函数传参时左值引用和右值引用的区别。根据引用[1]和引用[3],我们知道: -左值引用(T&)只能绑定到左值(有名字、有地址的对象)。-右值引用(T&&)只能绑定到右值(临时对象、字面量等)。 在函数传参时,使用引用(无论是左值引用还是右值引用)可以避免对象的拷贝,提高效率。但者绑定的对象不同,因此用途也不同。具体区别如下:1.**绑定对象不同**:-左值引用参数只能接受左值实参。-右值引用参数只能接受右值实参。 2. **用途不同**:-左值引用常用于函数需要修改实参,或者避免拷贝但需要保留原对象(非临时对象)的情况。-右值引用常用于实现移动语义(移动构造函数、移动赋值运算符)和完美转发,可以“窃取”临时对象的资源,避免深拷贝。3.**常量左值引用**(const T&)的特殊性:它可以绑定到左值和右值,因此当函数不想修改传入的参数,又想接受左值和右值时,可以使用常量左值引用。举例说明:```cpp#include <iostream>#include <string>//左值引用版本voidprocess(int&lref) {std::cout<< "lvalue reference: "<< lref <<std::endl;} //右值引用版本void process(int&&rref) {std::cout<< "rvaluereference:" <<rref<< std::endl; }int main() {inta =10;process(a);//调用左值引用版本process(20); //调用右值引用版本//常量左值引用可以接受左值和右值const int& cref1= a;//左值const int& cref2 =30;//右值return0;} ```在上面的例子中,`process`函数两个重载版本。当我们传递左值`a`时,调用左值引用版本;传递字面量`20`(右值)时,调用右值引用版本。 另外,引用[3]提到,右值引用主要用于移动语义和完美转发。例如: ```cppclassMyString{ public://移动构造函数MyString(MyString&&other)noexcept {//窃取other的资源data_= other.data_;size_ =other.size_;//将other置为空状态,避免重复释放other.data_= nullptr;other.size_ =0;}// ...其他成员};``` 在移动构造函数中,我们通过右值引用参数获取一个临时对象(右值),然后将其资源“移动”到新对象中,避免了深拷贝。总结:|特性|左值引用(T&)|右值引用(T&&)||--------------|---------------------|---------------------| |绑定对象|左值|右值| |主要用途|避免拷贝,修改实参|移动语义,完美转发| |可否绑定右值 |否(除非constT&)|是|因此,在函数参数设计时,根据需求选择:-如果函数需要修改传入的对象(且该对象不是临时对象),使用左值引用-如果函数需要处理临时对象并“窃取”其资源,使用右值引用-如果函数不需要修改传入的对象,且要同时接受左值和右值,使用常量左值引用(constT&)。 注意:右值引用参数本身是一个左值(因为它有名字),所以在函数内部如果需要继续传递它(如用于完美转发),需要使用`std::forward`来保持其值类别。</think>### C++函数传参:左值引用 vs 右值引用区别详解 #### 一、核心概念 1. **左值(lvalue)** - 有持久身份(可通过地址访问) - 有名字的对象(变量、函数等) - 示例:`int a = 10;` 中 `a` 是左值 - 可出现在赋值号左侧:`a = 20;` 2. **右值(rvalue)** - 临时对象或字面量 - 无持久身份(不能取地址) - 示例:`5`, `a+1`, `std::string("tmp")` - 通常出现在赋值号右侧:`int b = a + 1;` #### 二、引用类型对比 | 特性 | 左值引用 `T&` | 右值引用 `T&&` | |--------------------|-----------------------|-----------------------| | 绑定对象 | 左值 | 右值(临时对象) | | 主要用途 | 避免拷贝,修改原对象 | 移动语义,资源转移 | | 是否延长对象生命周期 | ❌ | ✅(绑定临时对象时) | | 函数重载 | 常规函数 | 移动构造/赋值函数 | | 典型场景 | 输入输出参数 | 临时对象处理 | #### 三、函数传参区别 ```cpp // 左值引用版本 void process(int& val) { val *= 2; // 可直接修改原对象 } // 右值引用版本 void process(int&& val) { // 可"窃取"资源,避免拷贝 int new_val = std::move(val); } ``` **调用示例**: ```cpp int main() { int a = 10; // 左值引用调用 process(a); // ✅ 绑定左值 cout << a; // 输出 20(值被修改) // 右值引用调用 process(5); // ✅ 绑定字面量(右值) process(std::move(a)); // ✅ 显式转为右值 // process(a); // ❌ 错误:不能绑定左值到右值引用 } ``` #### 四、关键区别分析 1. **资源处理方式** - 左值引用:操作原对象,不转移所有权 - 右值引用:可转移资源(如指针、内存),原对象置空 ```cpp // 移动构造函数示例 Vector(Vector&& other) : data(other.data), size(other.size) { other.data = nullptr; // 置空源对象 } ``` 2. **性能优化** - 右值引用避免深拷贝: ```cpp std::vector<std::string> v; v.push_back(std::string("hello")); // 移动语义 => 零拷贝 ``` 3. **类型推导规则** - 模板函数中 `T&&` 是万能引用(universal reference) ```cpp template<typename T> void relay(T&& arg) { // 可接受左右值 // 完美转发保持值类别 process(std::forward<T>(arg)); } ``` #### 五、使用场景建议 | 场景 | 推荐方式 | 原因 | |--------------------------|----------------|--------------------------| | 需要修改传入对象 | 左值引用 `T&` | 直接操作原对象 | | 处理临时对象 | 右值引用 `T&&` | 避免拷贝,资源转移 | | 只读访问(兼容左右值) | `const T&` | 可绑定所有类型 | | 实现移动语义 | `T&&` | 支持资源转移 | | 模板中的参数转发 | `T&&` + `std::forward` | 保持值类别 | > 关键原则:**右值引用用于标识可安全"销毁"的对象**,通过移动语义将资源所有权转移到新对象,避免不必要的复制开销[^3]。 --- ### 相关问题 1. 为什么移动构造函数参数必须是右值引用? 2. 如何实现完美转发(perfect forwarding)? 3. `std::move` 和 `std::forward` 的本质区别是什么? 4. 常量左值引用(`const T&`)为什么能绑定右值? 5. 在哪些场景下使用右值引用反而会降低性能?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值