C++中std::allocator的使用案例詳解
標(biāo)準(zhǔn)庫中包含一個(gè)名為allocator的類,允許我們將分配和初始化分離。使用allocator通常會提供更好的性能和更靈活的內(nèi)存管理能力。
new有一些靈活性上的局限,其中一方面表現(xiàn)在它將內(nèi)存分配和對象構(gòu)造組合在了一起。類似的,delete將對象析構(gòu)和內(nèi)存釋放組合在了一起。我們分配單個(gè)對象時(shí),通常希望將內(nèi)存分配和對象初始化組合在一起。因?yàn)樵谶@種情況下,我們幾乎肯定知道對象應(yīng)有什么值。當(dāng)分配一大塊內(nèi)存時(shí),我們通常計(jì)劃在這塊內(nèi)存上按需構(gòu)造對象。在此情況下,我們希望將內(nèi)存分配和對象構(gòu)造分離。這意味著我們可以分配大塊內(nèi)存,但只在真正需要時(shí)才真正執(zhí)行對象的創(chuàng)建操作(同時(shí)付出一定開銷)。一般情況下,將內(nèi)存分配和對象構(gòu)造組合在一起可能會導(dǎo)致不必要的浪費(fèi)。
標(biāo)準(zhǔn)庫allocator類定義在頭文件memory中,它幫助我們將內(nèi)存分配和對象構(gòu)造分離開來。它提供一種類型感知的內(nèi)存分配方法,它分配的內(nèi)存是原始的、未構(gòu)造的。類似vector,allocator是一個(gè)模板。為了定義一個(gè)allocator對象,我們必須指明這個(gè)allocator可以分配的對象類型。當(dāng)一個(gè)allocator對象分配內(nèi)存時(shí),它會根據(jù)給定的對象類型來確定恰當(dāng)?shù)膬?nèi)存大小和對齊位置。allocator支持的操作,如下:
allocatro分配的內(nèi)存是未構(gòu)造的(unconstructed)。我們按需要在此內(nèi)存中構(gòu)造對象。在新標(biāo)準(zhǔn)庫中,construct成員函數(shù)接受一個(gè)指針和零個(gè)或多個(gè)額外參數(shù),在給定位置構(gòu)造一個(gè)元素。額外參數(shù)用來初始化構(gòu)造的對象。類似make_shared的參數(shù),這些額外參數(shù)必須是與構(gòu)造的對象的類型相匹配的合法的初始化器。
在早期版本的標(biāo)準(zhǔn)庫中,construct只接受兩個(gè)參數(shù):指向創(chuàng)建對象位置的指針和一個(gè)元素類型的值。因此,我們只能將一個(gè)元素拷貝到未構(gòu)造空間中,而不能用元素類型的任何其它構(gòu)造函數(shù)來構(gòu)造一個(gè)元素。還未構(gòu)造對象的情況下就使用原始內(nèi)存是錯(cuò)誤的。為了使用allocator返回的內(nèi)存,我們必須用construct構(gòu)造對象。使用未構(gòu)造的內(nèi)存,其行為是未定義的。
當(dāng)我們用完對象后,必須對每個(gè)構(gòu)造的元素調(diào)用destroy來銷毀它們。函數(shù)destroy接受一個(gè)指針,對執(zhí)行的對象執(zhí)行析構(gòu)函數(shù)。我們只能對真正構(gòu)造了的元素進(jìn)行destroy操作。一旦元素被銷毀后,就可以重新使用這部分內(nèi)存來保存其它string,也可以將其歸還給系統(tǒng)。釋放內(nèi)存通過調(diào)用deallocate來完成。我們傳遞給deallocate的指針不能為空,它必須指向由allocate分配的內(nèi)存。而且,傳遞給deallocate的大小參數(shù)必須與調(diào)用allocate分配內(nèi)存時(shí)提供的大小參數(shù)具有一樣的值。
標(biāo)準(zhǔn)庫還為allocator類定義了兩個(gè)伴隨算法,可以在未初始化內(nèi)存中創(chuàng)建對象。它們都定義在頭文件memory中,如下:
在C++中,內(nèi)存是通過new表達(dá)式分配,通過delete表達(dá)式釋放的。標(biāo)準(zhǔn)庫還定義了一個(gè)allocator類來分配動態(tài)內(nèi)存塊。分配動態(tài)內(nèi)存的程序應(yīng)負(fù)責(zé)釋放它所分配的內(nèi)存。內(nèi)存的正確釋放是非常容易出錯(cuò)的地方:要么內(nèi)存永遠(yuǎn)不會被釋放,要么在仍有指針引用它時(shí)就被釋放了。新的標(biāo)準(zhǔn)庫定義了智能指針類型------shared_ptr、unique_ptr和weak_ptr,可令動態(tài)內(nèi)存管理更為安全。對于一塊內(nèi)存,當(dāng)沒有任何用戶使用它時(shí),智能指針會自動釋放它?,F(xiàn)代C++程序應(yīng)盡可能使用智能指針。
std::allocator是標(biāo)準(zhǔn)庫容器的默認(rèn)內(nèi)存分配器。你可以替換自己的分配器,這允許你控制標(biāo)準(zhǔn)容器分配內(nèi)存的方式。
以上內(nèi)容主要摘自:《C++Primer(Fifth Edition 中文版)》第12.2.2章節(jié)
下面是從其他文章中copy的測試代碼,詳細(xì)內(nèi)容介紹可以參考對應(yīng)的reference:
#include "allocator.hpp" #include <iostream> #include <memory> #include <string> #include <vector> namespace allocator_ { // reference: C++ Primer(Fifth Edition) 12.2.2 int test_allocator_1() { std::allocator<std::string> alloc; // 可以分配string的allocator對象 int n{ 5 }; auto const p = alloc.allocate(n); // 分配n個(gè)未初始化的string auto q = p; // q指向最后構(gòu)造的元素之后的位置 alloc.construct(q++); // *q為空字符串 alloc.construct(q++, 10, 'c'); // *q為cccccccccc alloc.construct(q++, "hi"); // *q為hi std::cout << *p << std::endl; // 正確:使用string的輸出運(yùn)算符 //std::cout << *q << std::endl; // 災(zāi)難:q指向未構(gòu)造的內(nèi)存 std::cout << p[0] << std::endl; std::cout << p[1] << std::endl; std::cout << p[2] << std::endl; while (q != p) { alloc.destroy(--q); // 釋放我們真正構(gòu)造的string } alloc.deallocate(p, n); return 0; } int test_allocator_2() { std::vector<int> vi{ 1, 2, 3, 4, 5 }; // 分配比vi中元素所占用空間大一倍的動態(tài)內(nèi)存 std::allocator<int> alloc; auto p = alloc.allocate(vi.size() * 2); // 通過拷貝vi中的元素來構(gòu)造從p開始的元素 /* 類似拷貝算法,uninitialized_copy接受三個(gè)迭代器參數(shù)。前兩個(gè)表示輸入序列,第三個(gè)表示 這些元素將要拷貝到的目的空間。傳遞給uninitialized_copy的目的位置迭代器必須指向未構(gòu)造的 內(nèi)存。與copy不同,uninitialized_copy在給定目的位置構(gòu)造元素。 類似copy,uninitialized_copy返回(遞增后的)目的位置迭代器。因此,一次uninitialized_copy調(diào)用 會返回一個(gè)指針,指向最后一個(gè)構(gòu)造的元素之后的位置。 */ auto q = std::uninitialized_copy(vi.begin(), vi.end(), p); // 將剩余元素初始化為42 std::uninitialized_fill_n(q, vi.size(), 42); return 0; } // reference: http://www.modernescpp.com/index.php/memory-management-with-std-allocator int test_allocator_3() { std::cout << std::endl; std::allocator<int> intAlloc; std::cout << "intAlloc.max_size(): " << intAlloc.max_size() << std::endl; int* intArray = intAlloc.allocate(100); std::cout << "intArray[4]: " << intArray[4] << std::endl; intArray[4] = 2011; std::cout << "intArray[4]: " << intArray[4] << std::endl; intAlloc.deallocate(intArray, 100); std::cout << std::endl; std::allocator<double> doubleAlloc; std::cout << "doubleAlloc.max_size(): " << doubleAlloc.max_size() << std::endl; std::cout << std::endl; std::allocator<std::string> stringAlloc; std::cout << "stringAlloc.max_size(): " << stringAlloc.max_size() << std::endl; std::string* myString = stringAlloc.allocate(3); stringAlloc.construct(myString, "Hello"); stringAlloc.construct(myString + 1, "World"); stringAlloc.construct(myString + 2, "!"); std::cout << myString[0] << " " << myString[1] << " " << myString[2] << std::endl; stringAlloc.destroy(myString); stringAlloc.destroy(myString + 1); stringAlloc.destroy(myString + 2); stringAlloc.deallocate(myString, 3); std::cout << std::endl; return 0; } // // reference: http://en.cppreference.com/w/cpp/memory/allocator int test_allocator_4() { std::allocator<int> a1; // default allocator for ints int* a = a1.allocate(1); // space for one int a1.construct(a, 7); // construct the int std::cout << a[0] << '\n'; a1.deallocate(a, 1); // deallocate space for one int // default allocator for strings std::allocator<std::string> a2; // same, but obtained by rebinding from the type of a1 decltype(a1)::rebind<std::string>::other a2_1; // same, but obtained by rebinding from the type of a1 via allocator_traits std::allocator_traits<decltype(a1)>::rebind_alloc<std::string> a2_2; std::string* s = a2.allocate(2); // space for 2 strings a2.construct(s, "foo"); a2.construct(s + 1, "bar"); std::cout << s[0] << ' ' << s[1] << '\n'; a2.destroy(s); a2.destroy(s + 1); a2.deallocate(s, 2); return 0; } } // namespace allocator_
GitHub: https://github.com/fengbingchun/Messy_Test
到此這篇關(guān)于C++中std::allocator的使用案例詳解的文章就介紹到這了,更多相關(guān)C++中std::allocator的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)拓?fù)渑判颍ˋOV網(wǎng)絡(luò))
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)拓?fù)渑判?,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04Windows平臺下配置VS Code的C++環(huán)境教程
這篇文章主要介紹了Windows平臺下配置VS Code的C++環(huán)境教程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12