看看下面的程序的輸出:
#include <stdio.h> |
這個沒有任何問題,因爲"hello world!"是一個字符串常量,存放在靜態數據區,
把該字符串常量存放的靜態數據區的首地址賦值給了指針,
所以returnStr函數退出時,該該字符串常量所在內存不會被回收,故能夠通過指針順利無誤的訪問。
但是,下面的就有問題:
#include <stdio.h> |
"hello world!"是一個字符串常量,存放在靜態數據區,沒錯,
但是把一個字符串常量賦值給了一個局部變量(char []型數組),該局部變量存放在棧中,
這樣就有兩塊內容一樣的內存,這是與前着最本質的區別,
當returnStr函數退出時,棧要清空,局部變量的內存也被清空了,
所以這時的函數返回的是一個已被釋放的內存地址,所以打印出來的是亂碼。
如果函數的返回值非要是一個局部變量的地址,那麼該局部變量一定要申明爲static類型。如下:
#include <stdio.h> |
這個問題可以通過下面的一個例子來更好的說明:
#include <stdio.h> |
運行輸出結果:
in s1 p=0xbff92efb |
這個結果正好應證了上面解釋,同時,還可是得出一個結論:
字符串常量,之所以稱之爲常量,因爲它可一看作是一個沒有命名的字符串且爲常量,存放在靜態數據區。
這裏說的靜態數據區,是相對於堆、棧等動態數據區而言的。
靜態數據區存放的是全局變量和靜態變量,從這一點上來說,字符串常量又可以稱之爲一個無名的靜態變量,
因爲"Hello world!"這個字符串在函數 s1和s2 中都引用了,但在內存中卻只有一份拷貝,這與靜態變量性質相當神似。
v
ly:CR �.r;��f,��f,ii-theme-font:minor-latin;mso-fareast-font-family:宋體;mso-fareast-theme-font:minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin'>重載的operator new必須含有一個size_t參數,表示要分配內存的對象的長度,同時必須返回一個指向等於這個長度的對象的指針。若沒有找到符合要求的存儲單元,構造函數將不被調用,另外需要一個表示失敗的返回值以外還應該拋出異常(可以自定義)。Operator delete參數爲一個指向由operatornew分配內存的void*(已調用析構函數後得到的指針),其返回類型爲void。
演示示例
3.3.2重載類中的new/delete
重載類中的new實際上創建的是一個static成員函數,該new只爲創建該類對象起作用,不會影響默認的全局版本new,但是需要注意名字隱藏的問題。
注意:任何類中只要提供了自己的operator new或operator new[],那麼就得同時提供對應的類相關版本的plain new,placement new以及nothrow new,否則根據名字隱藏的規則(將全局new遮掩掉了),將會發生沒有可用匹配的錯誤。
一旦爲類重載了operator new與operator delete,那麼無論何時創建這個類的對象,都將調用這些重載的運算符,但若創建該類的一個對象數組時,全局operator new將立即被調用,用來爲這個數組分配足夠的內存,因此要避免出現這種情況,需要重載operator new的數組版本:operator new[]與operator delete[]。
演示示例:(item 36 in exceptional c++)
1. //問題1:爲什麼B的delete有第二個參數而D沒有?2. class B 3. {4. public:5. virtual ~B();6. void operator delete ( void*,size_t ) throw();7. voidoperator delete[]( void*, size_t ) throw();8. void f( void*, size_t )throw();9. };10. class D : public B11. {12. public:13. void operator delete ( void* )throw();14. void operatordelete[]( void* ) throw();15. };16. void f()17. {18. //問題2:下面各個語句中,調用的是哪一個delete以及調用時的參數,爲什麼?19. D* pd1 = new D; 20. delete pd1;21. B* pb1 = new D;22. delete pb1;23. D* pd2 = new D[10];24. delete[] pd2;25. B* pb2 = new D[10];26. delete[] pb2;27. 28. //問題3:下面兩個賦值語句合法嗎?29. typedef void(B::*PMF)(void*, size_t); 30. PMFp1 = &B::f;31. PMF p2 =&B::operator delete;32. }3.4 內存分配失敗問題
A 內存分配失敗的報告方式:大多數new通過拋出bad_alloc異常來報告分配失敗;nothrownew則通過C中malloc方式報告失敗,即僅返回空指針,永遠不會拋出異常。
B 內存分配失敗的處理過程:通過set_new_handler調用錯誤處理函數new_handler,檢查指向函數的指針,若指針非0,則指向的函數被調用。
new_handler與set_new_handler的原型如下:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p)throw();
new_handler是一個typedef,表現出一個函數指針,該函數沒有參數也沒有傳回值,而set_new_handler是一個函數,需要一個new_handler參數並傳回一個new_handler。
Set_new_handler的參數指針指向的函數正是當operatornew無法配置足夠內存時,應該去調用的函數,其傳回值是一個函數指針,指向先前登陸過的new_handler。用法示例如下:
void nomorememory()
{
cerr << "unable to satisfy request for memory\n";
abort();
}
int main()
{
set_new_handler(nomorememory);
int *pbigdataarray = new int[100000000];
...
}