c++中类型用new和不用new的区别
解析一:
new創(chuàng)建類對象,使用完后需使用delete刪除,跟申請內(nèi)存類似。所以,new有時(shí)候又不太適合,比如在頻繁調(diào)用場合,使用局部new類對象就不是個(gè)好選擇,使用全局類對象或一個(gè)經(jīng)過初始化的全局類指針?biāo)坪醺痈咝А?/p>
一、new創(chuàng)建類對象與不new區(qū)別
下面是自己總結(jié)的一些關(guān)于new創(chuàng)建類對象特點(diǎn):
- new創(chuàng)建類對象需要指針接收,一處初始化,多處使用
- new創(chuàng)建類對象使用完需delete銷毀
- new創(chuàng)建對象直接使用堆空間,而局部不用new定義類對象則使用棧空間
- new對象指針用途廣泛,比如作為函數(shù)返回值、函數(shù)參數(shù)等
- 頻繁調(diào)用場合并不適合new,就像new申請和釋放內(nèi)存一樣
二、new創(chuàng)建類對象實(shí)例
1、new創(chuàng)建類對象例子:
CTest* pTest = new CTest();
delete pTest;
pTest用來接收類對象指針。
不用new,直接使用類定義申明:
CTest mTest;
此種創(chuàng)建方式,使用完后不需要手動(dòng)釋放,該類析構(gòu)函數(shù)會(huì)自動(dòng)執(zhí)行。而new申請的對象,則只有調(diào)用到delete時(shí)再會(huì)執(zhí)行析構(gòu)函數(shù),如果程序退出而沒有執(zhí)行delete則會(huì)造成內(nèi)存泄漏。
2、只定義類指針
這跟不用new申明對象有很大區(qū)別,類指針可以先行定義,但類指針只是個(gè)通用指針,在new之前并為該類對象分配任何內(nèi)存空間。比如:
CTest* pTest = NULL;
但使用普通方式創(chuàng)建的類對象,在創(chuàng)建之初就已經(jīng)分配了內(nèi)存空間。而類指針,如果未經(jīng)過
對象初始化,則不需要delete釋放。
3、new對象指針作為函數(shù)參數(shù)和返回值
下面是天緣隨手寫一個(gè)例子,不太嚴(yán)謹(jǐn)。主要示意一下類指針對象作為返回值和參數(shù)使用。
?
?
解析二:
我們都知道C++中有三種創(chuàng)建對象的方法,如下:
?
復(fù)制代碼 代碼如下:
#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;
}
第一種和第二種沒什么區(qū)別,一個(gè)隱式調(diào)用,一個(gè)顯式調(diào)用,兩者都是在進(jìn)程虛擬地址空間中的棧中分配內(nèi)存,而第三種使用了new,在堆中分配了內(nèi)存,而棧中內(nèi)存的分配和釋放是由系統(tǒng)管理,而堆中內(nèi)存的分配和釋放必須由程序員手動(dòng)釋放,所以這就產(chǎn)生一個(gè)問題是把對象放在棧中還是放在堆中的問題,這個(gè)問題又和堆和棧本身的區(qū)別有關(guān):
?
這里面有幾個(gè)問題:
1.堆和棧最大可分配的內(nèi)存的大小
2.堆和棧的內(nèi)存管理方式
3.堆和棧的分配效率
首先針對第一個(gè)問題,一般來說對于一個(gè)進(jìn)程棧的大小遠(yuǎn)遠(yuǎn)小于堆的大小,在linux中,你可以使用ulimit -s (單位kb)來查看一個(gè)進(jìn)程棧的最大可分配大小,一般來說不超過8M,有的甚至不超過2M,不過這個(gè)可以設(shè)置,而對于堆你會(huì)發(fā)現(xiàn),針對一個(gè)進(jìn)程堆的最大可分配的大小在G的數(shù)量級(jí)上,不同系統(tǒng)可能不一樣,比如32位系統(tǒng)最大不超過2G,而64為系統(tǒng)最大不超過4G,所以當(dāng)你需要一個(gè)分配的大小的內(nèi)存時(shí),請用new,即用堆。
其次針對第二個(gè)問題,棧是系統(tǒng)數(shù)據(jù)結(jié)構(gòu),對于進(jìn)程/線程是唯一的,它的分配與釋放由操作系統(tǒng)來維護(hù),不需要開發(fā)者來管理。在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí),這些存儲(chǔ)單元會(huì)被自動(dòng)釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,不同的操作系統(tǒng)對棧都有一定的限制。 堆上的內(nèi)存分配,亦稱動(dòng)態(tài)內(nèi)存分配。程序在運(yùn)行的期間用malloc申請的內(nèi)存,這部分內(nèi)存由程序員自己負(fù)責(zé)管理,其生存期由開發(fā)者決定:在何時(shí)分配,分配多少,并在何時(shí)用free來釋放該內(nèi)存。這是唯一可以由開發(fā)者參與管理的內(nèi)存。使用的好壞直接決定系統(tǒng)的性能和穩(wěn)定。
由上可知,但我們需要的內(nèi)存很少,你又能確定你到底需要多少內(nèi)存時(shí),請用棧。而當(dāng)你需要在運(yùn)行時(shí)才知道你到底需要多少內(nèi)存時(shí),請用堆。
最后針對第三個(gè)問題,棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率 比較高。堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會(huì)按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在 堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會(huì) 分 到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。
由上可知,能用棧則用棧。
?
復(fù)制代碼 代碼如下:
#include <stdio.h>
#include <stdlib.h>?
void main()
{
?int n,*p,i,j,m;
?printf("本程序可對任意個(gè)整數(shù)排序;\n");
?printf("請輸入整數(shù)的總個(gè)數(shù): ");
?scanf("%d",&n);
?p=(int *)calloc(n,sizeof(int));??? //運(yùn)行時(shí)決定內(nèi)存分配大小
?if(p==0)?? {
? printf("分配失敗!\n");?
? exit(1);?
?}
解析三:
舉個(gè)簡單的例子: 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的定義方式有何本質(zhì)不同?用哪種方式比較好? 最佳答案 p1有系統(tǒng)創(chuàng)建并釋放,你不要擔(dān)心會(huì)出現(xiàn)內(nèi)存泄露,但是生命期只有在本區(qū)域的大括號(hào)內(nèi),出了大括號(hào)就沒用了。P2是指針,要自己釋放,用不好很危險(xiǎn),用好了功能強(qiáng)大,因?yàn)樗梢再x值給全局的變量,一下子從局部變量變成全局變量,還能把對象作為函數(shù)返回值。------------------------------------------------
先定義一個(gè)類:
class A
{
public:
A();
virtual ~A();
...
...
};
類實(shí)現(xiàn)略。
用的時(shí)候:
A a;
a.成員函數(shù);
a.成員變量;
a 就是一個(gè)對象。
也可以這樣用:
A *a = new A;
a->成員函數(shù);
a->成員變量;
最后別忘了銷毀對象: delete[] a;
?
-----------------------------------------------
一個(gè)類的實(shí)例化對象所占空間的大小?
?
注意不要說類的大小,是類的對象的大小.
首先,類的大小是什么?確切的說,類只是一個(gè)類型定義,它是沒有大小可言的。
用sizeof運(yùn)算符對一個(gè)類型名操作,得到的是具有該類型實(shí)體的大小。
如果
Class A;
A obj;
那么sizeof(A)==sizeof(obj)
那么sizeof(A)的大小和成員的大小總和是什么關(guān)系呢,很簡單,一個(gè)對象的大小大于等于所有非靜態(tài)成員大小的總和。
為什么是大于等于而不是正好相等呢?超出的部分主要有以下兩方面:
1) C++對象模型本身
對于具有虛函數(shù)的類型來說,需要有一個(gè)方法為它的實(shí)體提供類型信息(RTTI)和虛函數(shù)入口,常見的方法是建立一個(gè)虛函數(shù)入口表,這個(gè)表可為相同類型的對象共享,因此對象中需要有一個(gè)指向虛函數(shù)表的指針,此外,為了支持RTTI,許多編譯器都把該類型信息放在虛函數(shù)表中。但是,是否必須采用這種實(shí)現(xiàn)方法,C++標(biāo)準(zhǔn)沒有規(guī)定,但是這幾戶是主流編譯器均采用的一種方案。
2) 編譯器優(yōu)化
因?yàn)閷τ诖蠖鄶?shù)CPU來說,CPU字長的整數(shù)倍操作起來更快,因此對于這些成員加起來如果不夠這個(gè)整數(shù)倍,有可能編譯器會(huì)插入多余的內(nèi)容湊足這個(gè)整數(shù)倍,此外,有時(shí)候相鄰的成員之間也有可能因?yàn)檫@個(gè)目的被插入空白,這個(gè)叫做“補(bǔ)齊”(padding)。所以,C++標(biāo)準(zhǔn)緊緊規(guī)定成員的排列按照類定義的順序,但是不要求在存儲(chǔ)器中是緊密排列的。
基于上述兩點(diǎn),可以說用sizeof對類名操作,得到的結(jié)果是該類的對象在存儲(chǔ)器中所占據(jù)的字節(jié)大小,由于靜態(tài)成員變量不在對象中存儲(chǔ),因此這個(gè)結(jié)果等于各非靜態(tài)數(shù)據(jù)成員(不包括成員函數(shù))的總和加上編譯器額外增加的字節(jié)。后者依賴于不同的編譯器實(shí)現(xiàn),C++標(biāo)準(zhǔn)對此不做任何保證。
C++標(biāo)準(zhǔn)規(guī)定類的大小不為0,空類的大小為1,當(dāng)類不包含虛函數(shù)和非靜態(tài)數(shù)據(jù)成員時(shí),其對象大小也為1。
如果在類中聲明了虛函數(shù)(不管是1個(gè)還是多個(gè)),那么在實(shí)例化對象時(shí),編譯器會(huì)自動(dòng)在對象里安插一個(gè)指針指向虛函數(shù)表VTable,在32位機(jī)器上,一個(gè)對象會(huì)增加4個(gè)字節(jié)來存儲(chǔ)此指針,它是實(shí)現(xiàn)面向?qū)ο笾卸鄳B(tài)的關(guān)鍵。而虛函數(shù)本身和其他成員函數(shù)一樣,是不占用對象的空間的。
我們來看下面一個(gè)例子:(此例子在Visual C++編譯器中編譯運(yùn)行)
#include <iostream>
using namespace std;
class?? A??
{??
};??
class?? B??
{??
char?? ch;??
void?? func()??
{??
}??
};??
class?? C??
{??
char?? ch1;??? //占用1字節(jié)
char?? ch2;?? //占用1字節(jié)
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擴(kuò)充為2個(gè)字,但是對象b為什么沒擴(kuò)充為1個(gè)字呢?大家?guī)兔鉀Q
cout<<sizeof(c)<<endl;//result=8??
//對象c實(shí)際上只有6字節(jié)有用數(shù)據(jù),但是按照上面第二點(diǎn)編譯器優(yōu)化,編譯器將此擴(kuò)展為兩個(gè)字,即8字節(jié)
cout<<sizeof(d)<<endl;//result=8??
}??
綜上所述:
一個(gè)類中,虛函數(shù)、成員函數(shù)(包括靜態(tài)與非靜態(tài))和靜態(tài)數(shù)據(jù)成員都是不占用類對象的存儲(chǔ)空間的。
對象大小=?? vptr(可能不止一個(gè))?? +?? 所有非靜態(tài)數(shù)據(jù)成員大小?? +?? Aligin字節(jié)大小(依賴于不同的編譯器)
總結(jié)
以上是生活随笔為你收集整理的c++中类型用new和不用new的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 查看 CPU 使用率
- 下一篇: c++中vector使用说明