区别pointers和references

本文深入探讨了C++中指针和引用的使用场景,指出引用必须始终指向一个对象,不能指向null;而指针则可以指向null。通过实例展示了如何根据变量的目的来选择使用指针还是引用,以及引用可能带来的效率优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++中提供两种间接参考对象:pointers和references。pointers使用“*”和“->”操作符,references则使用“ . ”。

但是什么时候使用哪种方式?通过学习《More Effective C++》的条款1学习总结了以下情况:

(1)一个references必须总代表某个对象,不可能存在null references。所以当你使用一个变量,其目的是用来指向代表另外一个对象,但是也有可能它不指向任何对象。那么你应该使用pointer。因为pointer可以指向null。换个角度,如果该变量始终需要指向一个对象,不可能使其变为null,那么你应该使用reference。

        例: char *pc = 'a';    pc = NULL ;  //正确,可以改变其值。

                 char& pc2 = *pc; //该语句表达的是pc2代表空指针的引用!!!!这是有害的行为。C++对此没有明确定义,会导致不可预期的后果!

       所以,请记住:永远不再考虑“reference 成为 null”的可能性。

(2)reference一定代表某个对象。C++要求其必须有初值。

       例: string & rs;  //错误,无初值!

                string s("xyz");     string& rs = s;//正确

          另外,使用references可能会比使用pointers更具有效率,因为它不用检测为NULL的情况。如果参数值是指针的话,还需要检测指针是否为NULL的情况。

(3)Pionters和references之间另一个重要的差异是,pointers可以被重新赋值,指向另一个对象,reference却总是指向它最初获得的对象。

          例: string s1("nacy");

                   string s2("chancy");

                   string& rs = s1;  //rs为s1的引用

                   string *ps = &s1; //ps为s1的指针

                   rs = s2;   //rs仍然代表s1,但是现在s1的值现在变成了“chancy”

                   ps = &s2;  //ps现在指向s2,s1没有变化。


  书中总结:当你知道你需要指向某个东西,而且绝不会改变指向其他东西。当你实现一个操作符而其语法需求无法通过pointer完成,你就应该选择references。任何其他时候,请采用pointers。


### 传引用传指针的区别 #### 性能差异 在性能方面,传引用通常优于传值的方式,因为它避免了创建参数副本的过程[^5]。然而,与传指针相比,两者之间的性能差距较小,但在某些情况下仍存在细微差别。例如,在C++中,传引用本质上是一个隐藏的指针传递机制,但它提供了更简洁的语法支持,使得开发者无需显式解引用即可访问实际数据[^1]。 对于大型对象或复杂结构体而言,无论是传指针还是传引用,都可以显著减少因深拷贝带来的额外开销。过需要注意的是,如果函数内部修改了引用所指向的内容,则这些更改会直接影响原始变量;而如果是通过指针完成相同的操作,则需要手动解除地址操作符`*`来间接访问目标位置的数据成员[^1]。 #### 安全性考量 从安全性角度来看,使用引用往往被认为更加安全可靠一些。这是因为一旦某个形参被声明为常量引用(const reference),那么即使该形式允许调用方将其绑定到右值表达式的结果之上(即临时对象),也无法改变这个关联起来的对象状态。相比之下,虽然也可以定义const类型的指针以达到相似效果,但由于程序员必须始终记得加上取址运算(&)才能正确初始化这样的指针,所以更容易犯错. 外值得注意的是,尽管java里并没有传统意义上的c风格裸露出来的物理存储单元地址概念,但是它里面的object references其实质上就是一种特殊形态下的"smart pointers",只过它们受到jvm严格管控而已.[^2] #### 使用场景分析 - **C++中的应用** - 当希望让接收端能够直接操纵发送过来的实际资源而非仅仅获得一份独立镜像的时候适合采用reference作为接口设计. - 如果只是想共享同一个实体而关心所有权归属关系的话则推荐利用raw pointer或者是智能版本(shared_ptr/unique_ptr). - **跨语言比较** - Python主要依赖duck typing哲学理念构建其动态类型体系架构,故此根本存在类似于其他静态强类型语言里的formal parameter passing modes区分; - JavaScript同样缺乏原生层面的支持去区别对待value vs ref semantics during assignment operations between variables holding objects or arrays etc.; 最后附带一段展示如何合理运用weak_ptr防止循环保持造成内存泄漏的小例子: ```cpp #include <iostream> #include <memory> class B; class A { public: ~A() {std::cout << "~A()\n";} void setB(std::shared_ptr<B> b_) {b = b_;} private: std::weak_ptr<B> b; }; class B { public: ~B() {std::cout << "~B()\n";} void setA(std::shared_ptr<A> a_) {a = a_;} private: std::weak_ptr<A> a; }; int main(){ auto pa = std::make_shared<A>(); auto pb = std::make_shared<B>(); pa->setB(pb); pb->setA(pa); } // Both destructors will be called properly due to weak_ptrs usage here instead of shared ones creating circular dependency otherwise. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值