保存指针?还是副本?

C++编程中的安全与效率
本文通过一个实例探讨了C++编程中安全与效率之间的权衡问题。具体讨论了一个类在使用const char*参数时,由于未妥善处理字符串副本而导致的潜在问题,并提出了良好的注释及代码安全性的重要性。
今天测试一段新代码的时候,发现一个BUG,原因是同事写的一个类,在对其实例调用execute()方法之前,需要用pushParam()方法把类型为const char *的参数“压”给该对象。
class Foo {
public:
    void pushParam(const char *param);
    bool execute();
};
从类的行为上来说,我理所当然地认为pushParam()会保存一份字符串的副本,原因是通常的STL算法或容器都是这样做,而且这样也更安全,更重要的是,在这里没有任何注释明确要求“这定的字串指针必须长时间(至不在Foo这个对象销毁之前)保持有效“。
而事实上,为了效率,Foo这个类的实现只是保存了字串的指针,而不是个副本,它假定这个参数是长期有效的,正好我这段新代码在这里push了一个临时string对象,问题就产生了......
其实这里没有孰是孰非的问题,问题的关键在于:
  1. 良好健全的注释很有必要
  2. 代码安全在绝大多数时候,胜过(所谓的)效率,之所以用“所谓的”,是因为在当今电脑的速度和空间下,保存一个字串的副本的开销,实在是微乎其微。
  3. 从DELPHI联想到,如果C++有引用计数的string,那么效率和安全都兼顾了。C++实现字串的引用计数相当方便,不同的是DELPHI把这一切隐藏在编译器的背后。
C++中,区分普通指针和函数指针主要取决于它们所指向的对象类型以及语法表示上的差异。以下是详细的解释: ### 普通指针 vs 函数指针 #### 定义与声明 - **普通指针**:通常是指向数据(如变量、数组元素等)的内存地址。它的定义包括基本类型标识符加上星号(*)来表明这是一个指针。例如: ```cpp int* pInt; // 指向整数类型的指针 char* pChar; // 指向字符类型的指针 ``` - **函数指针**:则是指向某段可执行代码(即函数入口点)。它不仅包含返回值类型信息还含有形参列表的信息,因此其声明较为复杂一些。 ```cpp void (*pFunc)(int); // 指向无返回值并且只有一个整型参数的函数的指针 double (*mathOp)(double, double); // 指向接受两个双精度浮点数值并返回一个同样类型的值的结果运算函数 ``` #### 分配及初始化 对于这两种不同种类的指针来说,在分配具体的引用目标时也有着明显的区别: - 对于**普通指针**,可以直接让它保存某个已知变量或对象的位置: ```cpp int value = 10; int *ptrValue = &value; ``` - 而对于**函数指针**,则需将其关联到实际存在的具体实现上,通常是通过赋值给某一确定的具体函数实例完成这一步骤: ```cpp void exampleFunction(int x){ /*...*/ } void (*fnPtr)(int) = exampleFunction; // 或者也可以写作 fnPtr = &exampleFunction; ``` #### 解引用操作 当你解引用一个普通的指针时候实际上获取到了其所指向位置处存储的数据内容副本;但是如果你尝试对一个函数指针做同样的事情,则会引发错误因为根本就没有所谓的“存放在那里”的东西——只有过程体而已。 正确做法应该是直接使用圆括号把参数列出来作为调用表达式的组成部分: ```cpp // 错误的做法 -> 尝试像对待常规变量一样访问 (*fnPtr)(argument); // 正确的方式-> 省略显式解引用来简化书写风格 fnPtr(argument); ``` 总结一下关键点在于: - 数据指针对应实体性的资源,而函数指针对应行为性的描述。 - 形状各异但作用域内唯一解析规则决定了二者不会混淆。 - 应尽量保持清晰直观易读性强的良好编码习惯以避免不必要的误解发生几率增加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值