std::vector
phải khởi tạo các giá trị trong mảng bằng cách nào đó, có nghĩa là một số hàm tạo (hoặc bản sao-hàm dựng) phải được gọi. Các hành vi của vector
(hoặc bất kỳ lớp container) là không xác định nếu bạn đã truy cập vào phần uninitialized của mảng như thể nó đã được khởi tạo.
Cách tốt nhất là sử dụng reserve()
và push_back()
, sao cho hàm tạo bản sao được sử dụng, tránh xây dựng mặc định.
Sử dụng mã ví dụ của bạn:
struct YourData {
int d1;
int d2;
YourData(int v1, int v2) : d1(v1), d2(v2) {}
};
std::vector<YourData> memberVector;
void GetsCalledALot(int* data1, int* data2, int count) {
int mvSize = memberVector.size();
// Does not initialize the extra elements
memberVector.reserve(mvSize + count);
// Note: consider using std::generate_n or std::copy instead of this loop.
for (int i = 0; i < count; ++i) {
// Copy construct using a temporary.
memberVector.push_back(YourData(data1[i], data2[i]));
}
}
Vấn đề duy nhất với gọi reserve()
(hoặc resize()
) như thế này là bạn có thể sẽ viện dẫn sao chép constructor thường xuyên hơn bạn cần. Nếu bạn có thể đưa ra dự đoán tốt về kích thước cuối cùng của mảng, thì tốt hơn là hãy reserve()
khoảng trắng một lần ngay từ đầu. Tuy nhiên, nếu bạn không biết kích thước cuối cùng, ít nhất số lượng bản sao sẽ ở mức trung bình tối thiểu.
Trong phiên bản hiện tại của C++, vòng lặp bên trong hơi không hiệu quả vì giá trị tạm thời được tạo trên ngăn xếp, sao chép được xây dựng vào bộ nhớ vectơ và cuối cùng là tạm thời bị hủy. Tuy nhiên phiên bản tiếp theo của C++ có một tính năng gọi là tham chiếu R-Value (T&&
) sẽ giúp ích.
Giao diện được cung cấp bởi std::vector
không cho phép tùy chọn khác, sử dụng một số lớp giống như nhà máy để tạo giá trị khác với mặc định. Đây là một ví dụ sơ bộ về mô hình này sẽ được thực hiện như thế nào trong C++:
template <typename T>
class my_vector_replacement {
// ...
template <typename F>
my_vector::push_back_using_factory(F factory) {
// ... check size of array, and resize if needed.
// Copy construct using placement new,
new(arrayData+end) T(factory())
end += sizeof(T);
}
char* arrayData;
size_t end; // Of initialized data in arrayData
};
// One of many possible implementations
struct MyFactory {
MyFactory(int* p1, int* p2) : d1(p1), d2(p2) {}
YourData operator()() const {
return YourData(*d1,*d2);
}
int* d1;
int* d2;
};
void GetsCalledALot(int* data1, int* data2, int count) {
// ... Still will need the same call to a reserve() type function.
// Note: consider using std::generate_n or std::copy instead of this loop.
for (int i = 0; i < count; ++i) {
// Copy construct using a factory
memberVector.push_back_using_factory(MyFactory(data1+i, data2+i));
}
}
Việc này có nghĩa là bạn phải tạo lớp vectơ của riêng mình. Trong trường hợp này nó cũng phức tạp những gì cần phải có được một ví dụ đơn giản. Nhưng có thể có những lúc sử dụng chức năng của nhà máy như thế này tốt hơn, ví dụ nếu chèn là có điều kiện trên một số giá trị khác, và bạn sẽ phải xây dựng một cách vô điều kiện một số điều vô cùng tốn kém ngay cả khi nó không thực sự cần thiết.
Lưu ý - sử dụng dự trữ() không phải là một giải pháp, vì bạn không thể truy cập một cách hợp pháp các dữ liệu đó là tại các địa điểm kết thúc() trở lên. –
Làm rõ thêm: nó không phải là các nhà xây dựng khởi tạo các giá trị để 0. Đó là thay đổi kích cỡ các cuộc gọi chèn, mà không. –
Bạn có thể cung cấp cho chúng tôi bản khai cấu trúc không? Cảm ơn ... :-) – paercebal