指针函数、函数指针和指针函数指针的全面总结

C++中指针函数、函数指针和指针函数指针的全面总结

一、核心概念区别

概念本质声明示例核心特征
指针函数返回指针的函数int* func(int);函数定义,返回值是指针类型
函数指针指向函数的指针int (*ptr)(int);变量,存储函数地址
指针函数指针指向指针函数的指针int* (*ptr)(int);指针,指向返回指针的函数

二、详细解析与C++现代替代方案

1. 指针函数(Pointer-Returning Function)

传统形式

int* createInt(int val) {return new int(val);
}

现代C++替代方案

// 使用智能指针
std::unique_ptr<int> createInt(int val) {return std::make_unique<int>(val);
}// 工厂函数示例
class Widget {};
std::shared_ptr<Widget> createWidget() {return std::make_shared<Widget>();
}

优势

  • 自动内存管理
  • 异常安全
  • 明确所有权语义

2. 函数指针(Function Pointer)

传统形式

int add(int a, int b) { return a + b; }
int (*operation)(int, int) = &add;// 使用
int result = operation(3, 4);

现代C++替代方案

// 使用std::function
#include <functional>
std::function<int(int, int)> op = [](int a, int b) { return a + b; };// 使用模板
template<typename F>
void applyOperation(F&& f) {f(3, 4);
}// Lambda表达式
auto multiply = [](int a, int b) { return a * b; };

对比优势

  • 支持lambda和函数对象
  • 类型更安全
  • 可存储状态(捕获上下文)
  • 更易读的语法

3. 指针函数指针(Pointer to Pointer-Returning Function)

传统形式

int* createArray(size_t size) {return new int[size];
}int* (*arrayCreator)(size_t) = &createArray;// 使用
int* arr = arrayCreator(10);

现代C++替代方案

// 使用智能指针和类型别名
using ArrayCreator = std::unique_ptr<int[]>(*)(size_t);
ArrayCreator creator = [](size_t size) { return std::make_unique<int[]>(size); 
};// 或使用std::function
std::function<std::unique_ptr<int[]>(size_t)> creator;

三、现代C++最佳实践总结

  1. 内存管理

    • 优先使用unique_ptr/shared_ptr
    • 避免裸指针所有权传递
  2. 回调机制

    // 传统(不推荐)
    void registerCallback(void (*callback)(int));// 现代(推荐)
    void registerCallback(std::function<void(int)> callback);
    
  3. 类型简化技巧

    // 复杂指针类型使用别名
    using ComplexHandler = void (*)(int*, const std::string&);// C++11后更推荐
    using SmartHandler = std::function<void(std::unique_ptr<int>, std::string_view)>;
    
  4. 成员函数处理

    // 传统成员函数指针
    void (MyClass::*memFunc)(int) = &MyClass::method;// 现代替代方案
    auto lambda = [obj = MyClass()](int x) { obj.method(x); };
    std::bind(&MyClass::method, &obj, std::placeholders::_1);
    

四、何时仍需使用传统形式

  1. 与C API交互时

    // qsort等C库函数需要的回调
    extern "C" void qsort(void*, size_t, size_t, int (*)(const void*, const void*));
    
  2. 极度性能敏感场景

    • 函数指针比std::function调用开销略低
  3. 嵌入式/系统级编程

    • 需要直接操作硬件地址时
  4. 模板元编程

    template<typename T, T (*Allocator)(size_t)>
    class CustomContainer { /*...*/ };
    

五、典型过渡示例

传统代码现代C++代码

// 传统
float* processData(int (*filter)(float), size_t size) {float* result = new float[size];// 处理...return result;
}// 现代
std::unique_ptr<float[]> processData(std::function<int(float)> filter, size_t size
) {auto result = std::make_unique<float[]>(size);// 处理...return result;
}

六、总结对比表

维度传统形式现代C++替代方案优势比较
返回值裸指针智能指针自动内存管理,异常安全
回调函数指针std::function/lambda更灵活,支持状态捕获
可读性复杂声明类型别名+auto代码更清晰
类型安全弱类型强类型系统编译期检查更严格
扩展性仅支持普通函数支持所有可调用对象兼容函数对象、成员函数等

现代C++不是要完全抛弃这些底层概念,而是提供更高层次的抽象,让开发者可以:

  1. 在需要控制底层时仍能使用传统方式
  2. 在大多数应用开发中使用更安全、更易用的替代方案
  3. 平滑过渡旧代码到现代实践

理解这些底层概念仍然很重要,它们是学习高级抽象的基础,也是处理特定场景的必要工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/900136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CherryStudio MCP实战(一)filesystem篇

随着DeepSeek的爆火&#xff0c;各行各业都在围绕着大模型寻找新质量生产力。简单来说&#xff0c;DeepSeek像是人的大脑&#xff0c;他可以推理&#xff0c;帮你思考一些问题&#xff0c;但是具体要做一些事情的时候&#xff0c;他还需要“手脚”来协同。MCP&#xff08;Model…

TCP基础篇(一)

文章目录 1.TCP 是如何保证可靠性的?2. 滑动窗口机制3 超时重传4.TCP 报文格式5. 什么是 TCP 协议5.1 如何唯一确定一个 TCP 连接 6.TCP 三次握手过程6.1 可以两次握手吗? 7.TCP 的四次挥手7.1 为什么客户端要等待2MSL&#xff1f; 8.linux 中查看 TCP 的连接9.TCP 为什么要有…

【Axure元件分享】时间范围选择器

时间范围选择器下拉选择开始时间和结束时间&#xff0c;实现效果如下。 源文件截图&#xff1a; 元件获取方式&#xff1a;

大模型学习一:deepseek api 调用实战以及参数介绍

一、说明 DeepSeek&#xff08;杭州深度求索人工智能基础技术研究有限公司&#xff09;是一家专注于大语言模型&#xff08;LLM&#xff09;研发的中国创新型科技公司&#xff0c;成立于2023年7月17日&#xff0c;由幻方量化孵化。其核心产品包括开源推理模型DeepSeek-R1、多模…

【Linux网络与网络编程】03.UDP Socket编程

一、UDP Socket编程接口 // 创建套接字 int socket(int domain, int type, int protocol); // 参数&#xff1a; // domain&#xff1a;域&#xff08;协议家族&#xff09;&#xff0c;这里使用 AF_INET 表示进行网络编程 // type&#xff1a;网络通信传输的类型&#xff0…

linux gcc

一、常用编译选项 ​基本编译 gcc [input].c -o [output] ​示例&#xff1a; gcc hello.c -o hello # 将 hello.c 编译为可执行文件 hello ./hello # 运行程序 ​分步编译 预处理&#xff1a;-E&#xff08;生成 .i 文件&#xff09; gcc -E hello.c -o hello…

若依框架二次开发——RuoYi-AI 集成本地大模型

文章目录 前提条件1. RuoYi-AI 已成功部署并运行2. Ollama 本地大模型已安装1. 配置本地大模型2. 切换至本地模型3. 开始对话总结本文将详细介绍如何在 RuoYi-AI 中集成本地 Ollama 大模型,使系统能够在 离线环境 下提供智能对话能力。 前提条件 在开始集成本地大模型之前,…

Flask学习笔记 - 模板渲染

Flask 模板渲染 模板是包含占位符的 HTML 文件 Flask 使用 Jinja2 模板引擎来处理模板渲染。模板渲染允许你将动态内容插入到 HTML 页面中&#xff0c;使得应用能够生成动态的网页内容。 创建模板&#xff1a;将 HTML 文件放在 templates 文件夹中&#xff0c;使用 Jinja2 占…

解码 from XXX import * - 导入的真相

文章目录 前言一、 什么是 from XXX import *?二、基本用法:导入的实际效果三、默认行为:无 __all__ 的情况四、与直接运行 XXX.py 的对比示例模块使用 from XXX import *直接运行 python example.py关键差异五、为什么需要注意 from XXX import *?最佳实践六、实际应用场景…

JavaScript 中常见的鼠标事件及应用

JavaScript 中常见的鼠标事件及应用 在 JavaScript 中&#xff0c;鼠标事件是用户与网页进行交互的重要方式&#xff0c;通过监听这些事件&#xff0c;开发者可以实现各种交互效果&#xff0c;如点击、悬停、拖动等。 在 JavaScript 中&#xff0c;鼠标事件类型多样&#xff0…

Nacos注册中心AP模式核心源码分析(单机模式)

文章目录 概述一、客户端启动主线流程源码分析1.1、客户端与Spring Boot整合1.2、注册实例&#xff08;服务注册&#xff09;1.3、发送心跳1.4、拉取服务端实例列表&#xff08;服务发现&#xff09; 二、服务端接收请求主线流程源码分析2.1、接收注册请求2.1.1、初始化注册表2…

prism WPF 模块

模块 DLL ModuleA 和 ModuleB 都要安装 Prism.Unity 引用方式1 项目引用 直接 在引用中添加项目引用 App.xaml.cs 添加模块 ConfigureModuleCatalog using ModuleA; using ModuleB; using Prism.Ioc; using Prism.Modularity; using Prism.Unity; using PrismWpfApp.ViewMo…

CSS:换行与不换行

一、CSS 不允许换行 在 CSS 中&#xff0c;有几种方法可以控制文本不换行&#xff1a; 1. 使用 white-space 属性 .no-wrap {white-space: nowrap; } white-space: nowrap; 会强制文本在一行显示&#xff0c;不换行。 2. 使用 overflow 和 text-overflow 通常与 white-sp…

JavaScript BOM、事件循环

目录 BOM&#xff08;浏览器对象模型&#xff09; 一、window 对象 1. 窗口控制 2. 定时器 二、location 对象 三、navigator 对象 四、history 对象 五、screen 对象 六、本地存储 1. localStorage 2. sessionStorage 七、BOM 应用场景 八、总结 JavaScript 执行…

k8s运维面试总结(持续更新)

一、你使用的promethues监控pod的哪些指标&#xff1f; CPU使用率 内存使用率 网络吞吐量 磁盘I/O 资源限制和配额&#xff1a;Prometheus可以监控Pod的资源请求和限制&#xff0c;确保它们符合预设的配额&#xff0c;防止资源过度使用。具体指标如container_spec_cpu_quota用于…

ubuntu20.04升级成ubuntu22.04

命令行 sudo do-release-upgrade 我是按提示输入y确认操作&#xff0c;也可以遇到配置文件冲突时建议选择N保留当前配置

Cortex-M​ 函数调用的入栈与出栈操作

在 ARM Cortex-M 系列单片机中,普通C函数调用的入栈(压栈)和出栈操作通常由编译器编译后生成的代码管理,而硬件仅负责部分关键操作。以下是详细分析: 1. 函数调用与返回的核心机制 (1) 硬件自动完成的部分 返回地址的保存: 当通过 BL(Branch with Link)或 BLX 指令调用…

DeepSeek能否用于对话系统(Chatbot)?技术解析与应用实例!

引言&#xff1a;Chatbot 的进化与挑战 你有没有发现&#xff0c;现在的AI聊天机器人越来越聪明了&#xff1f;无论是客服助手、智能语音设备&#xff0c;还是社交媒体上的自动回复&#xff0c;Chatbot&#xff08;对话系统&#xff09;已经渗透到我们生活的方方面面。但问题是…

多表查询的多与一

1.查寻表需要的条件 1.1.首先我们要了解查询表有哪些 1.1.1.多对一 多对一就是一个年表拥有例外一个表的多条数据 一个表对应立一个表的多条数据&#xff0c;另一个表对应这个表的多条数据 这个点被称为多对一 1.1.2.多对多 多对多简单来说就是需要一个中间商 中间商就…

配置文件、Spring日志

SpringBoot配置⽂件 SpringBoot⽀持并定义了配置⽂件的格式, 也在另⼀个层⾯达到了规范其他框架集成到SpringBoot的 ⽬的. 很多项⽬或者框架的配置信息也放在配置⽂件 中, ⽐如: 项⽬的启动端⼝ 数据库的连接信息(包含⽤⼾名和密码的设置) 第三⽅系统的调⽤密钥等信息 ⽤…