我在使用std :: list <std :: string>時偶然發現了std :: string的內存溢出問題內存泄漏 , 其中一條評論說: 程序員
中止使用
new
這麼多。 我看不到您在任何地方使用新產品的任何緣由。 您能夠在C ++中按值建立對象,這是使用該語言的巨大優點之一。 您沒必要在堆上分配全部內容。 不要像Java程序員那樣思考。 編程
我不肯定他的意思。 爲何要在C ++中儘量頻繁地經過值建立對象,它在內部有什麼不一樣? 我是否誤解了答案? 多線程
考慮一個「謹慎」的用戶,他記得將對象包裝在智能指針中: 函數
foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));
該代碼很危險,由於不能保證 在 T1
或T2
以前構造了shared_ptr
。 所以,若是new T1()
或new T2()
的一個在另外一個成功以後失敗,則第一個對象將被泄漏,由於不存在用於破壞和從新分配它的shared_ptr
。 工具
解決方案:使用make_shared
。 編碼
這再也不是問題:C ++ 17對這些操做的順序施加了約束,在這種狀況下,確保對
new()
每次調用都必須當即跟隨着相應智能指針的構造,而在其中沒有其餘操做之間。
這意味着,在調用第二個
spanew()
,能夠確保第一個對象已經包裝在其智能指針中,從而防止在引起異常的狀況下發生任何泄漏。
Barry
在另外一個答案中提供了對C ++ 17引入的新評估順序的更詳細說明。
操作系統
感謝@Remy Lebeau指出,這在C ++ 17下仍然是一個問題(儘管更少): shared_ptr
構造函數可能沒法分配其控制塊並拋出,在這種狀況下,傳遞給它的指針不會被刪除。 .net
解決方案:使用make_shared
。 線程
我發現錯過了一些儘量少的新事物的重要緣由:
new
運算符的執行時間不肯定 調用new
可能會或可能不會致使操做系統向您的進程分配新的物理頁面,若是您常常這樣作,可能會很慢。 或者它可能已經準備好合適的存儲位置,咱們不知道。 若是你的程序須要有一致的和可預測的執行時間(如在一個實時系統或遊戲/物理模擬),你須要避免new
在你的時間臨界循環。
new
是一個隱式線程同步 是的,您據說過,您的操做系統須要確保頁面表是一致的,所以調用new
將致使您的線程獲取隱式互斥鎖。 若是您一直從許多線程中調用new
,那麼您其實是在對線程進行序列化(我已經用32個CPU進行了此操做,每一個CPU都按下new
以得到每一個數百字節的數據,哎呀!這是調試的皇家皮塔餅)
諸如慢,碎片,易於出錯等之類的其餘問題已經在其餘答案中說起。
new
是新的goto
。
回想一下爲何goto
如此受到譴責:儘管goto
是功能強大的底層控制流的工具,但人們常常以沒必要要的複雜方式使用它,這使得代碼難以遵循。 此外,最有用和最容易閱讀的模式是在結構化的編程語句中編碼的(例如for
或while
); 最終的結果是,使用goto
做爲適當方法的代碼不多見,若是您很想編寫goto
,則可能作得很差(除非您真的知道本身在作什麼)。
new
與此相似-它一般用於使事情變得沒必要要地複雜和難以閱讀,而且能夠編碼的最有用的用法模式已編碼爲各類類。 此外,若是您須要使用尚沒有標準類的任何新用法模式,則能夠編寫本身的對它們進行編碼的類!
我什至認爲new
是比goto
更糟糕的 ,由於須要將new
和delete
語句配對。
像goto
同樣,若是您曾經認爲須要使用new
,則可能作得很差-尤爲是在類的實現以外,這樣作的目的是封裝全部您須要執行的動態分配。
還有一個以上全部正確答案的要點,這取決於您正在執行哪一種編程。 例如,在Windows中開發內核->堆棧受到嚴格限制,您可能沒法像在用戶模式下那樣出現頁面錯誤。
在這樣的環境中,新的或相似C的API調用是首選的,甚至是必需的。
固然,這僅僅是規則的例外。
使用new時,對象將分配給堆。 一般在預期擴展時使用。 當您聲明諸如
Class var;
它放在堆棧上。
您將始終必須使用new對放置在堆上的對象調用destroy。 這爲內存泄漏打開了可能。 放置在堆棧上的對象不容易發生內存泄漏!