在C&C++指针的惯用方法

C 和 C++ 中指针是核心特性,但两者的惯用法(idioms)有显著差异:C 语言依赖指针实现动态内存、数据结构、函数抽象;C++ 则通过智能指针、引用、RAII等机制减少裸指针使用,提升安全。

下面系统梳理 C/C++ 指针的最常用、最实用的惯用方法,涵盖安全使用、性能优化、现代替代方案等。

一、C 语言指针惯用法

1. 指针作为输出参数(模拟"引用")

cpp 复制代码
// 返回多个值
int parse_int(const char* str, int* out_value) {
    if (!str || !out_value) return -1; // 防御性检查
    *out_value = atoi(str);
    return 0; // success
}

// 使用
int val;
if (parse_int("123", &val) == 0) {
    printf("Parsed: %d\n", val);
}

✔️ C 无引用,用 T* 实现"写回"语义。

2. 指针遍历数组(高效且惯用)

cpp 复制代码
void print_array(int* arr, size_t n) {
    for (int* p = arr; p != arr + n; ++p) {
       printf("%d ", *p);
    }
}

✔️ 比下标更贴近硬件,常用于嵌入式/高性能代码。

3. 函数指针实现回调与多态

cpp 复制代码
typedef void (*Logger)(const char*);

void log_info(const char* msg) { printf("[INFO] %s\n", msg); }
void log_error(const char* msg) { printf("[ERROR] %s\n", msg); }

void process(Logger log_fn) {
    log_fn("Processing...");
}

// 使用
process(log_info);

✔️ Linux 内核、qsort、事件系统广泛使用。

二、C++ 指针惯用法(现代 C++)

核心原则:尽量避免裸指针(raw pointer),优先使用引用、智能指针、容器。

1. 用引用替代输出参数(更安全)

cpp 复制代码
bool parse_int(std::string_view str, int& out_value) {
    try {
        out_value = std::stoi(std::string(str));
        return true;
    } catch (...) {
        return false;
    }
}

// 使用
int val;
if (parse_int("123", val)) { /* ... */ }

✔️ 引用不可为空,语义更清晰。


2. 智能指针管理动态内存(RAII)

std::unique_ptr(独占所有权)
cpp 复制代码
auto ptr = std::make_unique<int>(42);
// 自动析构,无需手动 delete
std::shared_ptr(共享所有权)
cpp 复制代码
auto sp1 = std::make_shared<MyClass>();
auto sp2 = sp1; // 引用计数 +1

惯用法 :优先使用 make_unique / make_shared,避免裸 new

3. 裸指针仅用于"非拥有式观察"

cpp 复制代码
class Observer {
public:
    // 接收指针,但不负责 delete
    void watch(const Widget* widget) {
        if (widget) {
           current_ = widget; // 仅观察
        }
    }
private:
    const Widget* current_ = nullptr; // 观察者指针
};

4. 成员函数返回 this 指针(流式接口)

cpp 复制代码
class Builder {
    std::string data_;
public:
    Builder& add(const std::string& s) {
        data_ += s;
        return *this; // 返回引用(本质是 this 解引用)
    }
};

// 使用
Builder b;
b.add("Hello").add(" World");

5. "Pimpl" 惯用法(Pointer to Implementation)

cpp 复制代码
// widget.h
class Widget {
public:
    Widget();
    ~Widget(); 
    void doSomething();
private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};
cpp 复制代码
// widget.cpp
class Widget::Impl {
public:
    int data;
    void helper() { /* ... */ }
};

Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
void Widget::doSomething() { pImpl->helper(); }

优点:隐藏实现细节、减少编译依赖、提升 ABI 稳定性。

相关推荐
大圣编程4 小时前
Java 多维数组详解
java·开发语言
殳翰6 小时前
下服务器端开发流程及相关工具介绍(C++)
开发语言·c++
落寞的星星7 小时前
这个对象就包含了已经转换好的DFA和各种词法分析器运转所需要的参数。下一步,我们就可以用ScannerInfo对象创建出Scanner对象,请看下面的代码:
开发语言·c#
nothing&nowhere7 小时前
用 Python 做问卷数据清洗:无效样本检测与处理实战
开发语言·python·数据清洗·数据处理·问卷星·问卷星脚本·刷问卷
青瓦梦滋7 小时前
协议定制/序列化-反序列化(Linux视角)
linux·服务器·网络·c++
2601_961593428 小时前
Rust 开发环境配置繁琐?RustRover 开箱即用搞定编码调试
开发语言·后端·macos·rust
HZZD_HZZD8 小时前
DL/T 645-2026新国标深度解读与智能电表协议适配实战:从帧结构变化到Java采集器升级的全链路改造方案
java·开发语言
多加点辣也没关系10 小时前
JavaScript|第4章:类型转换
开发语言·javascript
聪慧的水蜜桃10 小时前
【YFIOs】用C#开发硬件之设备上云
开发语言·c#
yqcoder11 小时前
httpOnly 是什么,又有什么用?
开发语言·前端·javascript