C++函数调用的三种方式:从原理到实战的深度解析

1次阅读
没有评论

共计 1574 个字符,预计需要花费 4 分钟才能阅读完成。

image.webp

1. 为什么我们需要关注函数参数传递?

作为一个 C ++ 新手,我在写第一个交换两个变量的函数时就踩了坑:

void swap(int a, int b) { // 这样写根本交换不了!int temp = a;
    a = b;
    b = temp;
}

后来才知道原来 C ++ 有 三种截然不同的参数传递方式,选错了轻则性能下降,重则程序崩溃。

C++ 函数调用的三种方式:从原理到实战的深度解析

1.1 新手常见误区

  • 无脑用值传递:拷贝大对象(如 vector)时会产生性能黑洞
  • 指针滥用:忘记检查空指针或搞错内存生命周期
  • 忽视 const:该用 const 引用时没加,导致意外修改

2. 三种调用方式原理拆解

2.1 值传递(Pass by Value)

内存行为:
1. 调用时在栈上创建参数的完整副本
2. 原变量和副本完全独立

void process(std::string s) {/* 修改 s 不影响外部 */}

int main() {
    std::string data = "Hello";
    process(data); // 这里会发生 std::string 的拷贝构造
}

适用场景:
– 需要保护原始数据不被修改
– 传递内置类型(int/double 等)
– 函数内需要修改参数但不影响外部

2.2 指针传递(Pass by Pointer)

内存行为:
1. 传递变量地址的副本(指针本身被拷贝)
2. 通过解引用可修改原始数据

void resize(int* arr, int newSize) {if (arr != nullptr) // 必须检查!*arr = newSize; // 解引用修改
}

适用场景:
– 需要表示可选参数(用 nullptr)
– C 风格 API 兼容
– 明确需要指针语义(如链表节点)

2.3 引用传递(Pass by Reference)

内存行为:
1. 传递变量的别名(底层仍用指针实现)
2. 语法更简洁,天然非空

void capitalize(std::string& s) {if (!s.empty())
        s[0] = toupper(s[0]);
}

最佳实践:
– 输出参数(函数需要修改外部变量)
– 传递大对象避免拷贝
– 必须配合 const 使用:void print(const auto& obj)

3. 性能对比实测

测试代码片段:

struct BigData {char data[1024]; };

// 测试值传递
void byValue(BigData b) {/*...*/}

// 测试 const 引用
void byRef(const BigData& b) {/*...*/}

使用 -O2 编译后的关键汇编对比:
– 值传递:call memcpy@PLT(明显拷贝开销)
– 引用传递:直接操作原内存地址

4. 避坑指南

  1. 悬空引用:

    string& badFunc() {
        string local = "危险!";
        return local; // 局部变量销毁后引用失效
    }

  2. 指针所有权混淆:

    void process(int* p) {delete p; // 谁知道该不该在这里 delete?}

  3. 意外修改:

    void print(vector<int> data) { // 本意只是读取
        data.clear(); // 但实际修改了拷贝}

5. 实战思考题

问题:设计一个字符串处理函数,要求:
– 必选参数用 const 引用
– 可选参数用指针
– 输出参数用非 const 引用

参考答案结构:

void stringTransform(
    const std::string& input, // 必选输入
    std::string& output,      // 输出参数
    int* optionalParam = nullptr // 可选参数
) {if (optionalParam)
        output = input.substr(0, *optionalParam);
    else
        output = input;
}

6. 总结心得

经过这次深度探索,我发现:
– 小对象(<8 字节)直接传值反而更快
– 引用传递是日常最常用的方式
– 现代 C ++ 中原始指针应逐步被智能指针替代

建议搭配《Effective C++》第 20-22 条一起阅读,会有更体系化的理解。

正文完
 0
评论(没有评论)