前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >为什么我应该使用指针而不是对象本身

为什么我应该使用指针而不是对象本身

作者头像
ClearSeve
发布2022-02-10 19:10:30
发布2022-02-10 19:10:30
1.4K00
代码可运行
举报
文章被收录于专栏:ClearSeveClearSeve
运行总次数:0
代码可运行

问题

我之前一直使用 Java,现在开始转向 C++。

我发现使用 C++ 的人经常用指针表示对象,比如像下面这样:

代码语言:javascript
代码运行次数:0
运行
复制
Object *myObject = new Object;

而不是,

代码语言:javascript
代码运行次数:0
运行
复制
Object myObject;

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

代码语言:javascript
代码运行次数:0
运行
复制
myObject->testFunc();

而不是,

代码语言:javascript
代码运行次数:0
运行
复制
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 掉了,只剩下和基类相同的成员变量和属性。
代码语言:javascript
代码运行次数:0
运行
复制
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" off
gun(&d);   // OK, a Derived object IS-A Base object
hun(d);    // also OK, reference also doesn't slice
  1. 你希望表示对象是可选的(optional): 指针可以被赋值为 nullptr,也就是空的意思,你可以通过设置指针为 nullptr,来表达忽略该变量的含义。C++ 17 新增了 std::optional,那么这个问题也可以得到解决。
  2. 你想通过解耦编译单元来减少编译时间: 如果对象都是指针指向的,那么只需要这个类型的前向声明就可以。这可以分离编译过程的各个部分,会显著提高编译时间。
代码语言:javascript
代码运行次数:0
运行
复制
#include "B.h" // 必须 include 来包含类 B 的定义

class A; // 只需 A 的前向声明即可

func(A* a, B a)
{
}
  1. 兼容 C 库: C 库的接口大多都是以指针返回对象,这个时候你就不得不用指针。当然你也可以使用智能指针来封装它,这样使用起来就方便了。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年1月24日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 回答
    • 对象生命周期
    • 什么时候该使用 new?
    • 什么时候该使用指针?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档