我們在上一章說了如何使用這個vector動態數組,這章我們說說如何更好的使用它以及它是如何工作的。當你創建一個vector,然后使用push_back添加元素,當當前的vector的內存不夠時,會從內存中的舊位置復制到內存中的新位置,然后刪除刪除舊位置的內存,也就是說當我push_back,vector容量不夠添加元素就會調整大小,重新分配,這也就是將代碼拖慢的原因之一。是事實,我們需要不斷的重新分配,這是一個非常緩慢的操作,應該避免。我們如何避免復制對象,如果我們處理的是vector,特別是基于vector的對象,我們沒有存儲vector指針,我們存儲的是vector對象,那占的內存就更大了,所以我們要優化復制。
#include <iostream>
#include <string>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}//拷貝構造Vertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;//打印6次//vertices.push_back(Vertex(1, 2, 3));//vertices.push_back(Vertex(4, 8, 9));//vertices.push_back(Vertex(7, 5, 6));//打印3次vertices.reserve(3);vertices.push_back(Vertex(1, 2, 3));vertices.push_back(Vertex(4, 8, 9));vertices.push_back(Vertex(7, 5, 6));std::cin.get();//打印0次vertices.emplace_back(1, 2, 3);vertices.emplace_back(14, 4, 6);vertices.emplace_back(7, 8, 9);}
在上面這段代碼中,我們復制了6次(調用了6次拷貝構造函數),這個是為什么呢?當我們在push_back的時候,我們實際是在,主函數的當前幀中構造它,所以我們在main的棧上創建它,然后我們需要做的是,把它放到這個vector中,所以我們是從main函數中(把這個創建的vertex)放到實際的vector中。
在 C++ 中,std::vector
?是一個動態數組,它可以調整其大小以容納不同數量的元素。當你調用?reserve
?方法時,你告訴?vector
?它應該預先分配足夠的內存來存儲指定數量的元素,但并不會真正添加這些元素。這樣做的好處是,當你稍后添加元素到?vector
?時,它可能不需要重新分配內存(如果添加的元素數量沒有超過預留的數量),這可以提高效率,因為內存分配通常是一個昂貴的操作。
在我們的代碼中,由于預留了 3 個元素的空間,因此當你添加前三個元素時,不需要重新分配內存,所以不會調用拷貝構造函數(除了可能的隱式移動構造函數或復制省略,但這些在這個例子中都不適用,因為直接傳遞了臨時對象)。但是,如果你沒有調用?reserve
,并且?vector
?的初始容量小于你要添加的元素數量,那么在添加元素時可能需要重新分配內存。在重新分配內存時,舊的元素會被拷貝(或移動)到新的內存位置,這就會調用拷貝構造函數(或移動構造函數)。
當你使用?vertices.emplace_back(1, 2, 3);
(以及類似的?emplace_back
?調用)時,你實際上是在告訴?std::vector
?直接在其內部存儲中構造?Vertex
?對象,而不是先創建一個臨時對象然后再將其拷貝或移動到?vector
?中。這是?emplace_back
?相較于?push_back
?的主要優勢之一,因為它避免了不必要的拷貝或移動操作,從而提高了效率。
由于?emplace_back
?直接在?vector
?的內存中構造對象,它不會調用?Vertex
?的拷貝構造函數。相反,它會調用?Vertex
?的構造函數,直接傳遞參數給構造函數來構造對象。這就是為什么你在使用?emplace_back
?后沒有看到 "Copied!" 的輸出。而是三次Constructed!
#include <iostream>
#include <string>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){std::cout << "Constructed!" << std::endl;}//拷貝構造Vertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.reserve(3);vertices.emplace_back(1, 2, 3);vertices.emplace_back(14, 4, 6);vertices.emplace_back(7, 8, 9);std::cin.get();
}
運行上述代碼,你會看到 "Constructed!" 被打印了3次,而不是 "Copied!",因為?emplace_back
?直接在?vector
?的內存中構造了?Vertex
?對象。?