c++中类型用new和不用new的区别

2023-05-16

解析一:

new创建类对象,使用完后需使用delete删除,跟申请内存类似。所以,new有时候又不太适合,比如在频繁调用场合,使用局部new类对象就不是个好选择,使用全局类对象或一个经过初始化的全局类指针似乎更加高效。

一、new创建类对象与不new区别

下面是自己总结的一些关于new创建类对象特点:

  • new创建类对象需要指针接收,一处初始化,多处使用
  • new创建类对象使用完需delete销毁
  • new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
  • new对象指针用途广泛,比如作为函数返回值、函数参数等
  • 频繁调用场合并不适合new,就像new申请和释放内存一样

二、new创建类对象实例

1、new创建类对象例子:

CTest* pTest = new CTest();

delete pTest;

pTest用来接收类对象指针。

不用new,直接使用类定义申明:

CTest mTest;

此种创建方式,使用完后不需要手动释放,该类析构函数会自动执行。而new申请的对象,则只有调用到delete时再会执行析构函数,如果程序退出而没有执行delete则会造成内存泄漏。

2、只定义类指针

这跟不用new申明对象有很大区别,类指针可以先行定义,但类指针只是个通用指针,在new之前并为该类对象分配任何内存空间。比如:

CTest* pTest = NULL;

但使用普通方式创建的类对象,在创建之初就已经分配了内存空间。而类指针,如果未经过

对象初始化,则不需要delete释放。

3、new对象指针作为函数参数和返回值

下面是天缘随手写一个例子,不太严谨。主要示意一下类指针对象作为返回值和参数使用。

 

 

解析二:

我们都知道C++中有三种创建对象的方法,如下:

 

复制代码 代码如下:


#include <iostream>
using namespace std;

 

class A
{
private:
    int n;
public:
    A(int m):n(m)
    {
    }
    ~A(){}
};

int main()
{
    A a(1);  //栈中分配
    A b = A(1);  //栈中分配
    A* c = new A(1);  //堆中分配
  delete c;
    return 0;
}


第一种和第二种没什么区别,一个隐式调用,一个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,而栈中内存的分配和释放是由系统管理,而堆中内存的分配和释放必须由程序员手动释放,所以这就产生一个问题是把对象放在栈中还是放在堆中的问题,这个问题又和堆和栈本身的区别有关:

 

这里面有几个问题:
1.堆和栈最大可分配的内存的大小
2.堆和栈的内存管理方式
3.堆和栈的分配效率

首先针对第一个问题,一般来说对于一个进程栈的大小远远小于堆的大小,在linux中,你可以使用ulimit -s (单位kb)来查看一个进程栈的最大可分配大小,一般来说不超过8M,有的甚至不超过2M,不过这个可以设置,而对于堆你会发现,针对一个进程堆的最大可分配的大小在G的数量级上,不同系统可能不一样,比如32位系统最大不超过2G,而64为系统最大不超过4G,所以当你需要一个分配的大小的内存时,请用new,即用堆。

其次针对第二个问题,栈是系统数据结构,对于进程/线程是唯一的,它的分配与释放由操作系统来维护,不需要开发者来管理。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储单元会被自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,不同的操作系统对栈都有一定的限制。 堆上的内存分配,亦称动态内存分配。程序在运行的期间用malloc申请的内存,这部分内存由程序员自己负责管理,其生存期由开发者决定:在何时分配,分配多少,并在何时用free来释放该内存。这是唯一可以由开发者参与管理的内存。使用的好坏直接决定系统的性能和稳定。

由上可知,但我们需要的内存很少,你又能确定你到底需要多少内存时,请用栈。而当你需要在运行时才知道你到底需要多少内存时,请用堆。

最后针对第三个问题,栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率 比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在 堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会 分 到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

由上可知,能用栈则用栈。

 

复制代码 代码如下:


#include <stdio.h>
#include <stdlib.h> 
void main()
{
 int n,*p,i,j,m;
 printf("本程序可对任意个整数排序;\n");
 printf("请输入整数的总个数: ");
 scanf("%d",&n);
 p=(int *)calloc(n,sizeof(int));    //运行时决定内存分配大小
 if(p==0)   {
  printf("分配失败!\n"); 
  exit(1); 
 }

解析三:


举个简单的例子: class Point { private: int x; int y; public: void Set(int a,int b) { x=a; y=b; } void Print() { cout<<"("<<x<<","<<y<<")"<<endl; } }; void main() { Point p1; Point *p2=new Point(); p1.Set(1,2); p2->Set(4,5); p1.Print(); p2->Print(); delete p2; } 对象p1,p2的定义方式有何本质不同?用哪种方式比较好?  

最佳答案   

p1有系统创建并释放,你不要担心会出现内存泄露,但是生命期只有在本区域的大括号内,出了大括号就没用了。P2是指针,要自己释放,用不好很危险,用好了功能强大,因为他可以赋值给全局的变量,一下子从局部变量变成全局变量,还能把对象作为函数返回值。  

------------------------------------------------

先定义一个类:
class A
{
public:
A();
virtual ~A();
...
...
};

类实现略。

用的时候:
A a;
a.成员函数;
a.成员变量;
a 就是一个对象。


也可以这样用:
A *a = new A;
a->成员函数;
a->成员变量;
最后别忘了销毁对象: delete[] a;

 

-----------------------------------------------

一个类的实例化对象所占空间的大小?

 

注意不要说类的大小,是类的对象的大小.

首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。
用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。
如果
Class A;
A obj;
那么sizeof(A)==sizeof(obj)
那么sizeof(A)的大小和成员的大小总和是什么关系呢,很简单,一个对象的大小大于等于所有非静态成员大小的总和。
为什么是大于等于而不是正好相等呢?超出的部分主要有以下两方面:
1) C++对象模型本身
对于具有虚函数的类型来说,需要有一个方法为它的实体提供类型信息(RTTI)和虚函数入口,常见的方法是建立一个虚函数入口表,这个表可为相同类型的对象共享,因此对象中需要有一个指向虚函数表的指针,此外,为了支持RTTI,许多编译器都把该类型信息放在虚函数表中。但是,是否必须采用这种实现方法,C++标准没有规定,但是这几户是主流编译器均采用的一种方案。
2) 编译器优化
因为对于大多数CPU来说,CPU字长的整数倍操作起来更快,因此对于这些成员加起来如果不够这个整数倍,有可能编译器会插入多余的内容凑足这个整数倍,此外,有时候相邻的成员之间也有可能因为这个目的被插入空白,这个叫做“补齐”(padding)。所以,C++标准紧紧规定成员的排列按照类定义的顺序,但是不要求在存储器中是紧密排列的。
基于上述两点,可以说用sizeof对类名操作,得到的结果是该类的对象在存储器中所占据的字节大小,由于静态成员变量不在对象中存储,因此这个结果等于各非静态数据成员(不包括成员函数)的总和加上编译器额外增加的字节。后者依赖于不同的编译器实现,C++标准对此不做任何保证。

C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。

如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。

我们来看下面一个例子:(此例子在Visual C++编译器中编译运行)

#include <iostream>
using namespace std;
class   A  
{  
};  
class   B  
{  
char   ch;  
void   func()  
{  
}  
};  
class   C  
{  
char   ch1;    //占用1字节
char   ch2;   //占用1字节
virtual   void   func()  
{  
}  
};  
class   D  
{  
int   in;  
virtual   void   func()  
{  
}  
};  
void   main()  
{  
A   a;
B   b;
C   c;
D   d;
cout<<sizeof(a)<<endl;//result=1  
cout<<sizeof(b)<<endl;//result=1  //对象c扩充为2个字,但是对象b为什么没扩充为1个字呢?大家帮忙解决
cout<<sizeof(c)<<endl;//result=8  
//对象c实际上只有6字节有用数据,但是按照上面第二点编译器优化,编译器将此扩展为两个字,即8字节
cout<<sizeof(d)<<endl;//result=8  
}  

综上所述:

一个类中,虚函数、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的。

对象大小=   vptr(可能不止一个)   +   所有非静态数据成员大小   +   Aligin字节大小(依赖于不同的编译器)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++中类型用new和不用new的区别 的相关文章

  • 重载全局new和delete

    程序代码 如下所示 xff1a span class token macro property span class token directive keyword include span span class token string
  • 重载new和delete检测内存泄漏

    内存泄漏就是new出来的内存没有通过delete合理的释放 重载new和delete检测内存泄漏原理是 xff1a 在重载的new中记录内存分配情况 xff0c 在重载的delete中删除内存分配记录 xff0c 从而跟踪所有内存分配信息
  • c++ 中的重载全局new,delete

    最近做一个小项目 xff0c 对c 43 43 又有很多新的理解 实在不的不让人发出感叹 xff0c c 43 43 太强大了 xff0c 绝对不是一朝一夕就可以领悟她的内涵的 首先我们要清楚 xff0c 为什么我们要重载new xff0c
  • 重载new/delete运算符

    下面介绍用重载new delete运算符的方式来实现一个简单的内存泄露检测工具 xff0c 基本思想是重载全局new delete运算符 xff0c 被检测代码调用new和delete运算符时就会调用重载过的operator new和ope
  • 重构 - 消除重复的new创建

    如下 xff1a 有时会遇到这种重复的new创建 span class token keyword public span span class token keyword class span span class token class
  • 用new调用函数的四步走

    JS规定 xff0c 使用new调用函数会进行四步走 xff1a 1 函数体内会自动创建出一个空白对象 2 函数的上下文 xff08 this xff09 会自动指向这个对象 3 函数体内的语句会执行 4 函数会自动返回上下文对象 xff0
  • New Bing来了

    chatgpt免费体验入口网址 xff1a http chat xutongbao top 参考链接 xff1a https mp weixin qq com s x8RUxofqS43xkZM 5xnTAw
  • C++使用new 和new[]操作符分配内存时的调用栈跟踪显示2

    我们可以通过这个技术分析内存泄漏的调用函数和位置 include lt Windows h gt include lt ImageHlp h gt include lt iostream gt include lt string gt in
  • 2023 New Year‘s Resolution

    This Is Game 2023 New Year 39 s Resolution My 2022 ended with a day of game I am convinced that I am not to blame becaus
  • A new value is to be assigned to the field 'L_BOX'

    转载 xff1a https www cnblogs com aurora cj p 9353144 html DUMP A new value is to be assigned to the field 34 lt L BOX gt 3
  • 函数(new)

    函数 xff08 new 一 字符串处理函数 1 字符串的输入 xff08 1 xff09 scanf span class token macro property span class token directive keyword i
  • C++的new

    C 43 43 中的new其实是一个很糊弄人的术语 xff0c 它有两种不同的含义 xff0c new运算符 xff08 new operator xff09 和new函数 xff08 operator new xff09 xff0c 值得
  • internal/validators.js:120 throw new ERR_INVALID_ARG_TYPE(name, ‘string‘, value);

    npm 安装 nrm 运行 nrm ls 的时候报错 如下 解决方法 安装之后运行 nrm ls 报上面的错误信息 先寻找 这个 cli js 文件 安装完会有提示 找到 17行 注释掉原来的内容 或者删除17行 如下 const NRMR
  • 新bing/New bing配置和操作

    申请进入候补名单完成任务获得加速使用header editor插件防止跳转到国内bing使用user agent修改浏览器的ui
  • nginx: [emerg] BIO_new_file("/etc/nginx/ssl_key/server.crt") failed (SSL: error:02001002:syste

    Centos 7 5 nginx 43 web集群配置https报错 报错信息 root 64 lb01 conf d nginx t nginx emerg BIO new file 34 etc nginx ssl key server
  • 1. 两数之和【return new int[]{i, j}、hashtable.containsKey()、get、put】

    1 两数之和 给定一个整数数组 nums 和一个整数目标值 target xff0c 请你在该数组中找出 和为目标值 target 的那 两个 整数 xff0c 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 xff0c 数
  • Java—内部类

    It s possible to please a class definition within another class definition 内部类即定义在另一个类的内部的类 When you create an inner cla
  • 柯理化、mergeOptions、new的实现原理、reduce、flat

    1 什么是反柯理化 怎么实现 反柯里化 是一个泛型化的过程 它使得被反柯里化的函数 可以接收更多参数 Function prototype unCurrying function var that this return function
  • js中new 到底做了瓦特??比较new、Object.create、Object.setPrototypeOf

    实例化的时候我们都是这样 var box new BOX 那么new在中间有什么作用呢 new 先创建一个新对象b new Object 将构造函数作用域赋给新变量 b proto BOX prototype 执行构造函数中的代码 属性 方
  • 【C++】教大家在七夕new一个对象

    new是啥 new 是C 的关键字之一 它一般用来在堆上创建对象 但它与一般的创建对象的方法不同 它在创建对象时 会返回这个对象的指针 堆是啥 还有 和栈有什么区别 栈是由编译器自动分配和释放的 一般存放函数的参数值 局部变量的值等 速度较

随机推荐

  • 完整opencv(emgucv)人脸、检测、采集、识别、匹配、对比

    成对几何直方图匹配 public static string MatchHist string haarXmlPath 61 64 34 haarcascade frontalface alt tree xml 34 HaarCascade
  • OpenCV学习笔记——判断两张图的相似度

    判断两张图的相似度 方法 直方图对比法ORB算法 实验 1 直方图对比法 参考如何使用OpenCV3直方图方法进行人脸相似度对比 因为我的环境是VS2010 43 OpenCV2 4 8 xff0c 所以在原版的基础上做了一点小修改 inc
  • 【OpenCV】直方图应用:直方图均衡化,直方图匹配,对比直方图

    本文链接 xff1a https blog csdn net xiaowei cqu article details 7606607 前面介绍了 数字图像灰度直方图 xff0c 现在来尝试直方图的应用 直方图均衡化 直方图均衡化 xff08
  • C# Socket服务器及多客户端连接应用例程

    服务端代码 控制台示例 static List lt Socket gt Sockets 61 new List lt Socket gt static void Main string args int port 61 10 byte b
  • C#Socket文件传输(发送与接收代码)

    原文链接 xff1a http www cnblogs com reynoldchan p 3762014 html 这里是发送的代码 xff1a SendVarData是转码后发送函数 1 lt summary gt 2 发送文件 3 l
  • C# Socket服务端与客户端通信(包含大文件的断点传输)

    步骤 xff1a 一 服务端的建立 1 服务端的项目建立以及页面布局 2 各功能按键的事件代码 1 xff09 传输类型说明以及全局变量 2 xff09 Socket通信服务端具体步骤 xff1a xff08 1 xff09 建立一个Soc
  • C# Socket案例(服务端与客户端)

    本文链接 xff1a https blog csdn net qq 42203978 article details 80520299 服务端完整代码 using System using System Net using System N
  • C#中的Socket编程-TCP客户端

    TCP客户端 using System using System Collections Generic using System Linq using System Net using System Net Sockets using S
  • 最小花费(图论算法)

    Description 在n个人中 xff0c 某些人的银行账号之间可以互相转账 这些人之间转账的手续费各不相同 给定这些人之间转账时需要从转账金额里扣除百分之几的手续费 xff0c 请问A最少需要多少钱使得转账后B收到100元 Input
  • C#获取本机IP地址字符串

    1 using System Net 2 using System Net Sockets 3 4 lt summary gt 5 获取本机IP地址 6 lt summary gt 7 lt returns gt 本机IP地址 lt ret
  • C#中Socket通信用法实例详解

    本文实例讲述了C 中Socket通信用法 分享给大家供大家参考 具体如下 xff1a 一 UDP方式 xff1a 服务器端代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  • 内存溢出问题分析

    System OutOfMemoryException 大多是数据处理的过程中 xff0c 对内存资源的管控太过于粗放 建议对于非托管资源的使用不要过于随意 内存分配的时候使用内存池的模式 xff0c 避免内存泄露和内存碎片 你的指针可能成
  • C# GC 垃圾回收机制原理

    转载参照自以下文章 xff1a http www cnblogs com fdyang p 3456258 html c 销毁资源和释放内存 https www cnblogs com Jessy articles 2552839 html
  • c++中 结构体和类的区别

    区别 xff1a 结构是一种用关键字struct声明的自定义数据类型 与类相似 xff0c 也可以包含构造函数 xff0c 常数 xff0c 字段 xff0c 方法 xff0c 属性 xff0c 索引器 xff0c 运算符和嵌套类型等 xf
  • 结构体和类的区别

    结构体和类的区别 xff1a 在做一个项目时 xff0c 使用了较多的结构体 xff0c 并且存在一些结构体的嵌套 xff0c 即某结构体成员集合包含另一个结构体等 xff0c 总是出现一些奇怪的错误 xff0c 才终于下决心好好分析一下到
  • C++程序内存分配方式(堆与栈)

    一 内存布局 1 栈区 xff08 stack xff09 xff1a 由编译器自动分配释放 xff0c 存放函数的参数值 xff0c 局部变量值等 xff0c 其操作方法类似数据结构中的栈 2 堆区 xff08 heap xff09 xf
  • 值引用和引用问题分析

    在c 43 43 中 xff0c 声明一个全局变量A a xff0c 然后在一个局部函数中创建类型A c赋值给a xff0c 对于值类型 xff0c 如结构体等 xff0c 是在栈中分配内存c xff0c 然后拷贝其内存所有值给a xff0
  • vs中寄存器调试窗口可看出程序是多少位运行的及cpu寄存器使用情况

    如果不清楚程序是多少位运行的 xff0c 可在vs中的调试 gt 寄存器调试窗口查看寄存器的寻址位数 xff0c 如果是32位的exe则寄存器寻址显示32位 xff0c 64位的exe则显示64位寻址 1 根据IntPtr Size来判断
  • CentOS6 Squid代理服务器的安装与配置

    一 简介 代理服务器英文全称是Proxy Server xff0c 其功能就是代理网络用户去取得网络信息 Squid是一个缓存Internet 数据的软件 xff0c 其接收用户的下载申请 xff0c 并自动处理所下载的数据 当一个用户想要
  • c++中类型用new和不用new的区别

    解析一 xff1a new创建类对象 xff0c 使用完后需使用delete删除 xff0c 跟申请内存类似 所以 xff0c new有时候又不太适合 xff0c 比如在频繁调用场合 xff0c 使用局部new类对象就不是个好选择 xff0