日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ vector 使用详解

發布時間:2024/2/28 c/c++ 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ vector 使用详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

介紹兩個關鍵詞

元素訪問

迭代器

容量

修改操作

emplace()?&?emplace_back()

std::erase &?std::erase_if?(std::vector)


簡介

C++?的?vector?本質上是一個動態數組,它的元素是連續存儲的,這意味著不僅可以通過迭代器訪問元素,還可以使用指向元素的常規指針來對其進行訪問。可以將指向 vector 元素的指針傳遞給任何需要指向數組元素的指針的函數。

vector?的存儲是自動處理的,可以根據需要進行擴展和收縮。vector?通常比靜態數組占用更多的空間,因為分配了更多的內存來處理將來的增長。這樣,vector?不必在每次插入元素時都重新分配,而僅在附加內存耗盡時才需要重新分配。可以使用?capacity()?函數查詢已分配的內存總量。可以通過調用 shrink_to_fit()?將額外的內存返回給系統。就性能而言,重新分配空間通常是費時的操作。如果元素的數目是預先已知的,調用 reserve() 函數可以消除重新分配。

?

介紹兩個關鍵詞

(1) constexpr?是 C++11 中新增的關鍵字,其語義是?"常量表達式",也就是在編譯期可求值的表達式。最基礎的常量表達式就是字面值或全局變量/函數的地址或 sizeof 等關鍵字返回的結果,而其它常量表達式都是由基礎表達式通過各種確定的運算得到的。 constexpr 值可用于 enum、switch、數組長度等場合。

constexpr 所修飾的變量一定是編譯期可求值的,所修飾的函數在其所有參數都是 constexpr 時,一定會返回 constexpr。

constexpr?int?Inc(int?i) {return?i + 1; }constexpr?int?a = Inc(1);? // ok constexpr?int?b = Inc(cin.get());?// error! constexpr?int?c = a * 2 + 1;? // ok

constexpr 的好處:

(1)?是一種很強的約束,更好地保證程序的正確語義不被破壞。

(2)?編譯器可以在編譯期對 constexpr 的代碼進行非常大的優化,比如將用到的 constexpr 表達式都直接替換成最終結果等。

(3)?相比宏來說,沒有額外的開銷,但更安全可靠。

?

(2) noexcept?關鍵字告訴編譯器,函數中不會發生異常,這有利于編譯器對程序做更多的優化。如果在運行時,noexecpt 函數向外拋出了異常如果函數內部捕捉了異常并完成處理,這種情況不算拋出異常,程序會直接終止,調用 std::terminate() 函數,該函數內部會調用 std::abort() 終止程序。

?

元素訪問

at 通過邊界檢查訪問指定的元素

reference ? ? ? at(?size_type pos?); const_reference at(?size_type pos?)?const;

返回對指定位置的元素的引用?pos,并進行邊界檢查。如果 pos 不在容器范圍內,則會引發類型為?std::out_of_range?的異常。

?

operation[ ] 用于訪問指定的元素

reference ? ? ? operator[](?size_type pos?); const_reference operator[](?size_type pos?)?const;

返回對指定位置的元素的引用 pos。不執行邊界檢查。表明我們可以像使用數組一樣使用 vector。

#include <vector> #include <iostream>int main() {std::vector<int> numbers {2, 4, 6, 8};std::cout << "Second element: " << numbers[1] << '\n';numbers[0] = 5;std::cout << "All numbers:";for (auto i : numbers) {std::cout << ' ' << i;}std::cout << '\n'; }

?

front 用于訪問第一個元素

reference front(); const_reference front()?const;

返回對容器中第一個元素的引用未定義?front?在空容器上的調用。

?

back 用于訪問最后一個元素

reference back(); const_reference back()?const;

返回對容器中最后一個元素的引用空容器調用?back?會導致未定義的行為

#include <vector> #include <iostream>int main() {std::vector<char> letters {'o', 'm', 'g', 'w', 't', 'f'};if (!letters.empty()) {std::cout << "The first character is: " << letters.front() << '\n';std::cout << "The last character is: " << letters.back() << '\n';} }

?

data 用于直接訪問基礎數組

constexpr?T*?data()?noexcept;??????????????????????(since C++20) constexpr?const?T*?data()?const?noexcept;??????????(since C++20)

返回值:指向基礎元素存儲的指針。對于非空容器,返回的指針等于第一個元素的地址。如果 size()?為 0,則 data()?可能會或可能不會返回空指針。

?

迭代器

begin()?& cbegin()

iterator begin()?noexcept; const_iterator begin()?const?noexcept; const_iterator cbegin()?const?noexcept;

返回指向?vector?第一個元素迭代器。如果的 vector 值為空,則返回的迭代器將等于?end()

?

?

end()?& cend()

iterator end()?noexcept; const_iterator end()?const?noexcept; const_iterator cend()?const?noexcept;

返回指向?vector?的最后一個元素之后的迭代器。begin、end 與 cbegin、cend 的區別是后者是指向常量的指針,在使用的過程中不允許改變指向內容的值。此元素充當占位符;嘗試訪問它會導致未定義的行為。

#include <iostream> #include <vector> #include <string>int main() {std::vector<int> ints {1, 2, 4, 8, 16};std::vector<std::string> fruits {"orange", "apple", "raspberry"};std::vector<char> empty;// Sums all integers in the vector ints (if any), printing only the result.int sum = 0;for (auto it = ints.cbegin(); it != ints.cend(); it++)sum += *it;std::cout << "Sum of ints: " << sum << "\n";// Prints the first fruit in the vector fruits, without checking if there is one.std::cout << "First fruit: " << *fruits.begin() << "\n";if (empty.begin() == empty.end())std::cout << "vector 'empty' is indeed empty.\n"; }輸出: Sum of ints: 31 First fruit: orange vector 'empty' is indeed empty.

?

rbegin()?& crbegin()

reverse_iterator rbegin()?noexcept; const_reverse_iterator rbegin()?const?noexcept; const_reverse_iterator crbegin()?const?noexcept;

將反向迭代器返回給 reversed 的第一個元素 vector。它對應于 non-reversed 的最后一個元素 vector。如果向量為空,則返回的迭代器等于?rend()

?

?

rend()?& crend()

reverse_iterator rend()?noexcept; const_reverse_iterator rend()?const?noexcept; const_reverse_iterator crend()?const?noexcept;

返回反向迭代器,該迭代器返回 reversed 的最后一個元素之后的元素 vector。它對應于 non-reversed 的第一個元素之前的元素 vector。該元素充當占位符,嘗試訪問它會導致未定義的行為。

?

容量

empty()?檢查容器沒有元素,即是否 begin?()?==?end?()

constexpr?bool?empty()?const?noexcept; #include <vector> #include <iostream>int main() {std::cout << std::boolalpha;std::vector<int> numbers;std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';numbers.push_back(42);std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n'; }輸出: Initially, numbers.empty(): true After adding elements, numbers.empty(): false

?

size()?返回容器中元素的數量,即?std::distance(?begin?(), end?())

size_type size()?const?noexcept; #include <vector> #include <iostream>int main() { std::vector<int> nums {1, 3, 5, 7};std::cout << "nums contains " << nums.size() << " elements.\n"; }輸出: nums contains 4 elements.

?

max_size()返回由于系統或庫實現限制,容器可以容納的最大元素數

size_type max_size()?const?noexcept; #include <iostream> #include <vector>int main() {std::vector<char> s;std::cout << "Maximum size of a 'vector' is " << s.max_size() << "\n"; }輸出: Maximum size of a 'vector' is 9223372036854775807s

?

reserve()?將 vector 的容量增加到大于或等于的值?new_cap

void?reserve(?size_type new_cap?);

如果 new_cap 大于當前的?capacity(),則分配新的存儲,否則該方法不執行任何操作。reserve()?不會更改?vector?元素個數,如果 new_cap 大于?capacity(),則所有迭代器包括過去的迭代器)以及對元素的所有引用都將無效。否則,沒有迭代器或引用無效。

#include <cstddef> #include <new> #include <vector> #include <iostream>// minimal C++11 allocator with debug output template <class Tp> struct NAlloc {typedef Tp value_type;NAlloc() = default;template <class T> NAlloc(const NAlloc<T>&) {}Tp* allocate(std::size_t n){n *= sizeof(Tp);std::cout << "allocating " << n << " bytes\n";return static_cast<Tp*>(::operator new(n));}void deallocate(Tp* p, std::size_t n) {std::cout << "deallocating " << n*sizeof*p << " bytes\n";::operator delete(p);} }; template <class T, class U> bool operator==(const NAlloc<T>&, const NAlloc<U>&) { return true; } template <class T, class U> bool operator!=(const NAlloc<T>&, const NAlloc<U>&) { return false; }int main() {int sz = 100;std::cout << "using reserve: \n";{std::vector<int, NAlloc<int>> v1;v1.reserve(sz);for(int n = 0; n < sz; ++n)v1.push_back(n);}std::cout << "not using reserve: \n";{std::vector<int, NAlloc<int>> v1;for(int n = 0; n < sz; ++n)v1.push_back(n);} }輸出: using reserve: allocating 400 bytes deallocating 400 bytes not using reserve: allocating 4 bytes allocating 8 bytes deallocating 4 bytes allocating 16 bytes deallocating 8 bytes allocating 32 bytes deallocating 16 bytes allocating 64 bytes deallocating 32 bytes allocating 128 bytes deallocating 64 bytes allocating 256 bytes deallocating 128 bytes allocating 512 bytes deallocating 256 bytes deallocating 512 bytes

?

capacity()?返回容器當前已分配空間的元素的個數。

size_type capacity()?const?noexcept;

?

shrink_to_fit()?請求刪除未使用的容量將?capacity()?減小為?size()

void?shrink_to_fit();????(since C++11)

如果發生重新分配,則所有迭代器包括過去的結束迭代器以及對元素的所有引用都將無效。如果沒有發生重新分配,則沒有迭代器或引用無效。

#include <iostream> #include <vector>int main() {std::vector<int> v;std::cout << "Default-constructed capacity is " << v.capacity() << '\n';v.resize(100);std::cout << "Capacity of a 100-element vector is " << v.capacity() << '\n';v.clear();std::cout << "Capacity after clear() is " << v.capacity() << '\n';v.shrink_to_fit();std::cout << "Capacity after shrink_to_fit() is " << v.capacity() << '\n'; } 輸出: Default-constructed capacity is 0 Capacity of a 100-element vector is 100 Capacity after clear() is 100 Capacity after shrink_to_fit() is 0

?

修改操作

clear() 清除元素

void?clear()?noexcept;

clear 清除容器中的所有元素調用之后,size()?返回零。使所有引用包含元素的引用,指針或迭代器無效。

?

insert() 插入元素

(1)iterator insert(?const_iterator pos,?const?T&?value?); (2)iterator insert(?const_iterator pos, T&&?value?); (3)iterator insert(?const_iterator pos, size_type count,?const?T&?value?); (4)template<?class?InputIt?>iterator insert(?const_iterator pos, InputIt first, InputIt last?); (5)iterator insert(?const_iterator pos,?std::initializer_list<T>?ilist?);

(1-2)?value?在之前插入 pos。

(3)?插入?count 個 value 副本到 pos 之前 。

(4) 將?[first, last) 范圍內的元素插入 pos 之前。

(5) 將?ilist?插入 pos 之前

如果新的?size()?大于舊的?capacity()則導致重新分配。如果新的?size()?大于?capacity(),則所有迭代器和引用均無效。否則,只有插入點之前的迭代器和引用保持有效。

#include <iostream> #include <vector>void print_vec(const std::vector<int>& vec) {for (auto x: vec) {std::cout << ' ' << x;}std::cout << '\n'; }int main () {std::vector<int> vec(3,100);print_vec(vec);auto it = vec.begin();it = vec.insert(it, 200);print_vec(vec);vec.insert(it,2,300);print_vec(vec);// "it" no longer valid, get a new one:it = vec.begin();std::vector<int> vec2(2,400);vec.insert(it+2, vec2.begin(), vec2.end());print_vec(vec);int arr[] = { 501,502,503 };vec.insert(vec.begin(), arr, arr+3);print_vec(vec); }輸出: 100 100 100 200 100 100 100 300 300 200 100 100 100 300 300 400 400 200 100 100 100 501 502 503 300 300 400 400 200 100 100 100

?

erase() 從容器中刪除指定的元素

iterator erase(?const_iterator pos?); iterator erase(?const_iterator first, const_iterator last?);

(1)?刪除處的元素?pos

(2)?刪除范圍內的元素 [first, last)。

點或點之后使迭代器和引用無效,包括?end()?迭代器。迭代器 pos 必須有效且可取消引用。因此,end()?迭代器有效,但不可取消引用)不能用作的值 pos。first 如果滿足以下條件,則不需要取消迭代器 first==last:刪除空范圍是無操作的。

#include <vector> #include <iostream>int main( ) {std::vector<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};for (auto &i : c) {std::cout << i << " ";}std::cout << '\n';c.erase(c.begin());for (auto &i : c) {std::cout << i << " ";}std::cout << '\n';c.erase(c.begin()+2, c.begin()+5);for (auto &i : c) {std::cout << i << " ";}std::cout << '\n';// Erase all even numbers (C++11 and later)for (auto it = c.begin(); it != c.end(); ) {if (*it % 2 == 0) {it = c.erase(it);} else {++it;}}for (auto &i : c) {std::cout << i << " ";}std::cout << '\n'; }輸出: 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 6 7 8 9 1 7 9

?

push_back() 將給定元素添加到容器末尾

void?push_back(?const?T&?value?);???(1) void?push_back(?T&&?value?);????? ??(2)

(1) 使用?value 的副本初始化新元素。

(2)?value被移到新元素中。

如果新的?size()?大于?capacity()則所有迭代器和引用包括過去的迭代器)都將失效。否則,只有過去的迭代器是無效的。由于隱式調用了 reserve(size()+ 1)?的等效項,某些實現還會導致重新分配超過最大的 size?時引發?std::length_error

#include <vector> #include <iostream> #include <iomanip>int main() {std::vector<std::string> numbers;numbers.push_back("abc");std::string s = "def";numbers.push_back(std::move(s));std::cout << "vector holds: ";for (auto&& i : numbers) std::cout << std::quoted(i) << ' ';std::cout << "\nMoved-from string holds " << std::quoted(s) << '\n'; }輸出: vector holds: "abc" "def" Moved-from string holds ""

?

pop_back() 刪除容器的最后一個元素

void?pop_back();

刪除容器的最后一個元素,pop_back?未定義在空容器上的調用。迭代器對最后一個元素的引用以及?end()?迭代器均無效。

#include <vector> #include <iostream>template<typename T> void print(T const & xs) {std::cout << "[ ";for(auto const & x : xs) {std::cout << x << ' ';}std::cout << "]\n"; }int main() {std::vector<int> numbers;print(numbers); numbers.push_back(5);numbers.push_back(3);numbers.push_back(4);print(numbers); numbers.pop_back();print(numbers); }輸出: [ ] [ 5 3 4 ] [ 5 3 ]

?

resize() 調整容器

void?resize(?size_type count?);????????????????????????????????(1) void?resize(?size_type count,?const?value_type&?value?);????? ?(2)

調整容器的大小以包含?count?元素。如果當前大小大于 count,則容器將縮小為其第一個 count 元素。如果當前大小小于 count,需要額外拷貝值 value。在將大小調整為更小時,vector?容量不會減少,因為這將使所有迭代器失效,而是等效調用 pop_back()?導致迭代器失效的情況??

#include <iostream> #include <vector> int main() {std::vector<int> c = {1, 2, 3};std::cout << "The vector holds: ";for(auto& el: c) std::cout << el << ' ';std::cout << '\n';c.resize(5);std::cout << "After resize up to 5: ";for(auto& el: c) std::cout << el << ' ';std::cout << '\n';c.resize(2);std::cout << "After resize down to 2: ";for(auto& el: c) std::cout << el << ' ';std::cout << '\n'; }輸出: The vector holds: 1 2 3 After resize up to 5: 1 2 3 0 0 After resize down to 2: 1 2

?

swap() 交換容器

void?swap(?vector&?other?)?noexcept;???????(since C++17)

與?other?容器完成交換。不對單個元素調用任何移動,復制或交換操作。

#include <vector> #include <iostream>void printVector(std::vector<int>& vec) {for (int a : vec){std::cout << a << " ";} }int main() {std::vector<int> v1{1, 2, 3};std::vector<int> v2{7, 8, 9};std::cout << "v1: ";printVector(v1);std::cout << "\nv2: ";printVector(v2);std::cout << "\n-- SWAP\n";v2.swap(v1);std::cout << "v1: ";printVector(v1);std::cout << "\nv2: ";printVector(v2); }輸出: v1: 1 2 3 v2: 7 8 9 -- SWAP v1: 7 8 9 v2: 1 2 3

?

?

emplace()?&?emplace_back()

C++11 新標準引入了三個新成員:emplace_front、emplace 和 emplace_back,這些操作構造而不是拷貝元素。這些操作分別對應 push_front、insert 和 push_back,允許將元素放置在容器頭部、一個指定位置之前或容器尾部。

當調用 push 或 insert 成員函數時,我們將元素類型的對象傳遞給它們,這些對象被拷貝到容器中。而當我們調用一個 emplace 成員函數時,則是將參數傳遞給元素類型的構造函數。emplace 成員使用這些參數在容器管理的內存空間中直接構造元素。

emplace 函數的參數根據元素類型而變化,參數必須與元素類型的構造函數相匹配。emplace 函數在容器中直接構造元素。傳遞給 emplace 函數的參數必須與元素類型的構造函數相匹配。

emplace()

template<?class...?Args?>? iterator emplace(?const_iterator pos, Args&&...?args?);????(since C++11)

將新元素直接插入容器的?pos?之前。元素是通過?std::allocator_traits::construct 構造的,通常使用 placement-new 在容器提供的位置就地構造元素。參數 args... 作為?std::forward?<?Args?>?(?args?)?... 轉發給構造函數。如果新的?size()?大于?capacity(),則所有迭代器和引用均無效。否則,只有插入點之前的迭代器和引用保持有效。

?

emplace_back()

template<?class...?Args?> reference emplace_back(?Args&&...?args?);????????????(since C++17)

將新元素附加到容器的末尾。該元素是通過?std::allocator_traits::construct 構造的,通常使用 placement-new 在容器提供的位置就地構造該元素。參數 args... 作為?std::forward?<?Args?>?(?args?)?... 轉發給構造函數。如果新的?size()?大于?capacity()則所有迭代器和引用(包括過去的迭代器)都將失效。否則,只有過去的迭代器是無效的。?

?

處理基礎數據類型:

// reference: http://www.cplusplus.com/reference/vector/vector/emplace_back/ int test() {{ /*template <class... Args>void emplace_back (Args&&... args);*/std::vector<int> myvector = { 10, 20, 30 };myvector.emplace_back(100);myvector.emplace_back(200);std::cout << "myvector contains:";for (auto& x : myvector)std::cout << ' ' << x;std::cout << '\n';}{ /*template <class... Args>iterator emplace (const_iterator position, Args&&... args);*/std::vector<int> myvector = { 10, 20, 30 };auto it = myvector.emplace(myvector.begin() + 1, 100);myvector.emplace(it, 200);myvector.emplace(myvector.end(), 300);std::cout << "myvector contains:";for (auto& x : myvector)std::cout << ' ' << x;std::cout << '\n';}return 0; }

?

處理對象:

#include <vector> #include <string> #include <iostream>struct President {std::string name;std::string country;int year;President(std::string p_name, std::string p_country, int p_year): name(std::move(p_name)), country(std::move(p_country)), year(p_year){std::cout << "I am being constructed.\n";}President(President&& other): name(std::move(other.name)), country(std::move(other.country)), year(other.year){std::cout << "I am being moved.\n";}President& operator=(const President& other) = default; };int main() {std::vector<President> elections;std::cout << "emplace_back:\n";elections.emplace_back("Nelson Mandela", "South Africa", 1994);std::vector<President> reElections;std::cout << "\npush_back:\n";reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));std::cout << "\nContents:\n";for (President const& president: elections) {std::cout << president.name << " was elected president of "<< president.country << " in " << president.year << ".\n";}for (President const& president: reElections) {std::cout << president.name << " was re-elected president of "<< president.country << " in " << president.year << ".\n";} }輸出: emplace_back: I am being constructed.push_back: I am being constructed. I am being moved.Contents: Nelson Mandela was elected president of South Africa in 1994. Franklin Delano Roosevelt was re-elected president of the USA in 1936.

?

emplace_back() 與 push_back() 對比:

// reference: https://corecplusplustutorial.com/difference-between-emplace_back-and-push_back-function/ class Dat {int i;std::string ss;char c;public:Dat(int ii, std::string s, char cc) :i(ii), ss(s), c(cc) { }~Dat() { } };int test_emplace_4() {std::vector<Dat> vec;vec.reserve(3);vec.push_back(Dat(89, "New", 'G')); // efficiency lesser//vec.push_back(678, "Newer", 'O'); // error,push_back can’t accept three argumentsvec.emplace_back(890, "Newest", 'D'); // work fine, efficiency is also morereturn 0; }

?

?

std::erase &?std::erase_if?(std::vector)

template<?class?T,?class?Alloc,?class?U?> constexpr?typename?std::vector<T,Alloc>::size_typeerase(std::vector<T,Alloc>&?c,?const?U&?value);??????(1) (since C++20)template<?class?T,?class?Alloc,?class?Pred?> constexpr?typename?std::vector<T,Alloc>::size_typeerase_if(std::vector<T,Alloc>&?c, Pred pred);????????(2) (since C++20)

(1) 從容器中刪除所有等于?value?的元素。相當于:

auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r;

?

(2)?pred?從容器中擦除所有滿足謂詞的元素。相當于:

auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; #include <iostream> #include <numeric> #include <vector>void print_container(const std::vector<char>& c) {for (auto x : c) {std::cout << x << ' ';}std::cout << '\n'; }int main() {std::vector<char> cnt(10);std::iota(cnt.begin(), cnt.end(), '0');std::cout << "Init:\n";print_container(cnt);std::erase(cnt, '3');std::cout << "Erase \'3\':\n";print_container(cnt);auto erased = std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });std::cout << "Erase all even numbers:\n";print_container(cnt);std::cout << "In all " << erased << " even numbers were erased.\n"; }輸出: Init: 0 1 2 3 4 5 6 7 8 9 Erase '3': 0 1 2 4 5 6 7 8 9 Erase all even numbers: 1 3 7 9 In all 5 even numbers were erased.

?

總結

以上是生活随笔為你收集整理的C++ vector 使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。