C++ 为什么经常用指针方式来使用对象

使用 C++ 时,我们经常用指针表示对象,比如像下面这样:

Object *myObject = new Object;

而不是:

Object myObject;

或者在调用成员函数的时候,都会这样:

myObject->testFunc();

而不是:

myObject.testFunc();

对于现代 C++ (尤其是 C++ 11 之后),大量使用 new 动态分配是不明智的选择。

下面从两个方面来解释:

  1. 什么时候该使用 new?

  2. 什么时候该使用指针?

对象生命周期

上面两种创建对象的语句有什么不同呢?

对于 Object myObject;该对象被创建在栈上,它的特点就是脱离作用域后会自动销毁。而对于 new Object(),它会在堆上动态创建一个对象,它的特点就是即使脱离作用域,该对象也会一直存在,除非你手动释放(delete)它,否则就会出现内存泄漏。

什么时候该使用 new?

  1. 你需要延长对象生命周期。 意思是说你想一直使用某个地址位置的变量,而不是它的副本,对于后者,我们更应该使用 Object myObject; 的语法。

  2. 你需要很多内存。 大家都知道,栈空间比堆空间小的多。

当你确实要用动态内存分配的话,应该用智能指针或者其它的 RAII 技术来管理这部分资源。

什么时候该使用指针?

除了动态分配内存之外,原始指针还有其它用途。

  1. 引用语义(reference semantics): 有的时候,你希望函数传递进来的参数不是一份副本(copy),因为创建副本的代价很大。这个时候,你就可以通过指针。不过 C++ 11 已经有了移动(move)语义,这个问题就不用担心了。

  2. 多态(polymorphic): 对于多态类型,指针和引用可以避免对象被切片(slice)。切片的意思就是说:在函数传参处理多态变量时,如果一个派生类对象在向上转换(upcast),用的是传值的方式,而不是指针和引用,那么,这个派生类对象在 upcast 以后,将会被 slice 成基类对象,也就是说,派生类中独有的成员变量和方法都被 slice 掉了,只剩下和基类相同的成员变量和属性。

class Base { ... };class Derived : public Base { ... };void fun(Base b) { ... }void gun(Base* b) { ... }void hun(Base& b) { ... }Derived d;fun(d);    // oops, all Derived parts silently "sliced" offgun(&d);   // OK, a Derived object IS-A Base objecthun(d);    // also OK, reference also doesn't slice
  1. 你希望表示对象是可选的(optional): 指针可以被赋值为 nullptr,也就是空的意思,你可以通过设置指针为 nullptr,来表达忽略该变量的含义。C++ 17 新增了 std::optional,那么这个问题也可以得到解决。

  2. 你想通过解耦编译单元来减少编译时间: 如果对象都是指针指向的,那么只需要这个类型的前向声明就可以。这可以分离编译过程的各个部分,会显著提高编译时间。

#include "B.h" // 必须 include 来包含类 B 的定义class A; // 只需 A 的前向声明即可func(A* a, B a){}
  1. 兼容 C 库: C 库的接口大多都是以指针返回对象,这个时候你就不得不用指针。当然你也可以使用智能指针来封装它,这样使用起来就方便了。
  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中的共享指针使用方式可以通过使用智能指针来实现。在C++11及以上的标准中,可以使用std::shared_ptr来管理共享资源。 以下是使用共享指针的基本步骤: 1. 包含头文件: ```cpp #include <memory> ``` 2. 创建共享指针: ```cpp std::shared_ptr<int> sharedPtr(new int); // 使用new关键字初始化指针,引用计数为1 ``` 3. 共享指针的拷贝: ```cpp std::shared_ptr<int> sharedPtr2 = sharedPtr; // 创建sharedPtr的副本,引用计数加1 ``` 4. 访问指针所指向的对象: ```cpp int value = *sharedPtr; // 解引用共享指针获取对象的值 ``` 5. 释放共享指针: ```cpp sharedPtr.reset(); // 引用计数减1,如果引用计数为0,则释放指针所指向的对象内存 ``` 6. 检查共享指针是否为空: ```cpp if (sharedPtr != nullptr) { // 共享指针不为空,可以访问其所指向的对象 } ``` 7. 使用共享指针作为函数参数: ```cpp void foo(std::shared_ptr<int> ptr) { // 在函数内部使用共享指针 } std::shared_ptr<int> sharedPtr(new int); foo(sharedPtr); // 将共享指针作为函数参数传递 ``` 注意事项: - 避免使用原始指针与共享指针混合使用,这可能导致引用计数错误。 - 避免循环引用,即两个或多个共享指针相互引用,导致引用计数无法减为0,从而导致内存泄漏。 这是一种常见的使用共享指针方式,但在实际使用时,请根据具体场景和需求选择适合的智能指针类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cpp编程小茶馆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值