原文点击这里

问题描述

我刚从 Java 转到使用 C++ 进行面向对象开发,我发现一个很让我非常困惑的问题:C++ 中经常出现使用对象指针,而不是直接使用对象本身的代码,比如下面这个例子:

C++

Object myObject = new Object;
1
Object
myObject = new Object;
而不是使用:

C++

Object myObject;
1
Object myObject;
要不就是调用对象的方法(比如 testFunc())时不使用这种方式:

C++

myObject.testFunc();
1
myObject.testFunc();
而是得写成这样:

C++

myObject->testFunc();
1
myObject->testFunc();
我不明白代码为什么要写成这种形式,我能想到的是指针方式是直接访问内存,这么写代码可以提高代码效率以及执行速度,是这样的么?

最佳回复

来自 Joseph Mansfield

非常不幸,你在代码中遇到这么多的动态内存分配,但这个只能说明有现在有太多不合格的 C++ 程序员。

这么说吧,你的两个问题本质上是同个问题。第一个问题是,应该何时使用动态分配(使用 new 方法)?第二问题是,什么时候该使用指针?

最先要牢记的重点是,你应该根据实际需求选择合适的方法。 一般来说,使用定义对象的方式比起使用手工动态分配(或new指针)的方式会更加合理以及安全。

动态分配

你的提问中,所列出的两种分配对象方式的主要区别在于对象的生存期。通过 Object myObject 方式定义对象,对象的生存期是在其作用域内自维护(automatic storage),这个意味着程序离开对象的作用域之后,对象将被自动销毁。当通过 new Object() 方式分配对象时,对象的生存期是动态的,这个意味着若不显式地 detete 对象,对象将一直存在。你应该只在必要的时候使用动态分配对象。换句话说,只要有可能,你应该首选定义可自维护的对象。

这里是两个常见需要动态分配对象的情况:

分配不限制作用域的对象,对象存储在其特定的内存中,而不是在内存中存储对象的拷贝。如果对象是可以拷贝/移动的,一般情况下你应该选择使用定义对象的方式。
定义的对象会消耗大量内存,这时可能会耗尽栈空间。如果我们永远不需要考虑这个问题那该多好(实际大部分情况下,我们真不需要考虑),因为这个本身已经超出 C++ 语言的范畴,但不幸的是,在我们实际的开发过程中却不得不去处理这个问题。
当你确实需要动态分配对象时,应该将对象封装在一个智能指针(smart pointer)或其他提供RAII机制的类型中(类似标准的 container)。智能指针提供动态对象的所有权语义(ownership),具体可以看一下std::unique_ptr 和 std::shared_ptr 这两个例子。如果你使用得当,基本上可以避免自己管理内存(具参见 Rule of Zero)。

指针

当然,不使用动态分配而采取原始指针(raw pointer)的用法也很常见,但是大多数情况下动态分配可以取代指针,因此一般情况应该首选动态分配的方法,除非你遇到不得不用指针的情况。

  1. 使用引用语义(reference semantics)的情况。有时你可能需要通过传递对象的指针(不管对象是如何分配的)以便你可以在函数中去访问/修改这个对象的数据(而不是它的一份拷贝),但是在大多数情况下,你应该优先考虑使用引用方式,而不是指针,因为引用就是被设计出来实现这个需求的。注意,采用这种方式,对象生存期依旧在其作用域内自维护。当然,如果通过传递对象拷贝可以满足要求的情况下是不需要使用引用语义。

  2. 使用多态的情况。通过传递对象的指针或引用调用多态函数(根据入参类型不同,会调用不同处理函数)。如果你的设计就是可以传递指针或传递引用,显然,应该优先考虑使用传递引用的方式。

  3. 对于入参对象可选的情况,常见的通过传递空指针表示忽略入参。如果只有一个参数的情况,应该优先考虑使用缺省参数或是对函数进行重载。要不然,你应该优先考虑使用一种可封装此行为的类型,比如 boost::optional (或者std::optional,已经在 C++ 14 草案 n3797 14 中发布 )。

  4. 通过解耦编译类型依赖减少编译时间的情况。使用指针的一个好处在于可以用于前向声名(forward declaration)指向特定类型(如果使用对象类型,则需要定义对象),这种方式可以减少参与编译的文件,从而显著地提高编译效率,具体可以看 Pimpl idiom 用法。

  5. 与C库或C风格的库交互的情况。此时只能够使用指针,这种情况下,你要确保的是指针使用只限定在必要的代码段中。指针可以通过智能指针的转换得到,比如使用智能指针的get成员函数。如果C库操作分配的内存需要你在代码中维护并显式地释放时,可以将指针封装在智能指针中,通过实现 deleter 从而可以有效的地释放对象。

[转] C++中为什么要用指针,而不直接使用对象?的更多相关文章

  1. c++中的引用与指针的区别

    http://blog.csdn.net/lyd_253261362/article/details/4323691 c++中的引用与指针的区别 ★ 相同点: 1. 都是地址的概念: 指针指向一块内存 ...

  2. MFC关于多线程中传递窗口类指针时ASSERT_VALID出错的另类解决 转

    MFC关于多线程中传递窗口类指针时ASSERT_VALID出错的另类解决   在多线程设计中,许多人为了省事,会将对话框类或其它类的指针传给工作线程,而在工作线程中调用该类的成员函数或成员变量等等. ...

  3. VC++中有关句柄和指针及其转换(转)

    原文转自 https://blog.csdn.net/jearmy/article/details/47030011 1.MFC窗口的句柄和指针的转换 (1) 一般窗口对象都会有一个其对应的句柄变量, ...

  4. C++中引用传递与指针传递区别

    C++中引用传递与指针传递区别 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值.值传递过程 ...

  5. LWIP协议中tcp_seg结构相关指针的个人理解

    我曾经写在新浪博客上面,后来复制到这,图片就不行了. 原文地址转载  LWIP协议中tcp_seg结构相关指针的个人理解(http://blog.sina.com.cn/s/blog_7e586985 ...

  6. C语言中的数组和指针以及字符串

    数组名同时也是该数组首元素的地址,而指针提供了一种用来使用地址的符号方法,因此指针能够很有效地处理数组. 将一个整数加给指针,这个整数会和指针所指类型的字节数相乘,然后所得的结果会加到初始地址上 da ...

  7. MFC类中获得其它类指针

    当用VC++的Application Wizard生成除了CDialog Basiced以外的应用程序时,将自动产生视图类.文档类.主帧窗口类.应用程序类等等.一般来说,程序的核心数据及操作在文档类中 ...

  8. C++中使用const修饰指针

    在本文中呢,主要讲解四个方面,即:常量数据的与否和常量指针的与否中const如何对指针进行修饰: 1.指向非常量数据的常量指针 对于一个指向非常量数据的常量指针,我们应该清楚的知道,在这我们注重的是指 ...

  9. C++中值传递、指针传递、引用传递的总结

    C++中值传递.指针传递.引用传递的总结   指针传递和引用传递一般适用于:函数内部修改参数并且希望改动影响调用者.对比值传递,指针/引用传递可以将改变由形参"传给"实参(实际上就 ...

  10. 尝试在条件“$(_DeviceSdkVersion) >= 21”中对计算结果为“”而不是数字的“$(_DeviceSdkVersion)

    晚上搞xamarin ,运行xamarin项目好好的,不知道怎么回事,一次运行xamarin android项目的时候,部署失败,以前也是遇到这样的错误. 尝试在条件"$(_DeviceSd ...

随机推荐

  1. maven的pom.xml文件详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  2. List接口特有功能

    List 有序的 有整数索引 允许重复使用 特有功能: void add(int index, E element)   //指定位置添加元素 E get()int index)            ...

  3. docker挂载目录的深入研究

    转载一篇很好的文章: https://www.cnblogs.com/ivictor/p/4834864.html

  4. 【笔记】Python基础一 :变量,控制结构,运算符及数据类型之数字,字符串,列表,元组,字典

    一,开发语言介绍 高级语言:Java,C#,Python  ==>产生字节码 低级语言:C,汇编                   ==>产生机器码 高级语言开发效率高,低级语言运行效率 ...

  5. docker for ubuntu 18 安装

    官网地址: https://docs.docker.com/install/linux/docker-ce/ubuntu/ docker的作用:解决不同机器之间的环境差异问题,方便迁移. 0. 卸载旧 ...

  6. 模拟退火算法-旅行商问题-matlab实现

    整理一下数学建模会用到的算法,供比赛时候参考食用. —————————————————————————————————————————— 旅行商问题(TSP): 给定一系列城市和每对城市之间的距离,求 ...

  7. SQL 数据开发(经典)转贴

    数据开发(经典) 1.按姓氏笔画排序: Select * From TableName Order By CustomerName Collate Chinese_PRC_Str oke_ci_as ...

  8. weblogic中配置数据源

    Weblogic数据源配置 一.配置数据源 1.点击数据源,进入数据源配置页面,点击新建后选择一般数据源 2.输入名称和jndi名称(两个输入一样即可)后点击下一步 3.选择驱动后点击下一步 4.输入 ...

  9. 使用JS在页面进行数据处理时显示等待画面

    使用js在页面进行数据处理期间显示等待画面: 在页面选择执行函数进行数据处理期间,显示等待画面. <script> function fun(the,row_id) { //测试函数 // ...

  10. Biopython 安装使用

    Biopython 官网:https://biopython.org/ 安装 Biopython  https://biopython.org/wiki/Download 可以使用 pip 进行安装, ...