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