Pertimbangkan cuplikan berikut:
#include <array>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
huge_type t;
}
Jelas itu akan crash pada sebagian besar platform, karena ukuran tumpukan standar biasanya kurang dari 20MB.
Sekarang pertimbangkan kode berikut:
#include <array>
#include <vector>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
std::vector<huge_type> v(1);
}
Anehnya itu juga crash! Traceback (dengan salah satu versi libstdc ++ terbaru) mengarah ke include/bits/stl_uninitialized.h
file, di mana kita dapat melihat baris berikut:
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());
Mengubah ukuran vector
konstruktor harus secara default menginisialisasi elemen, dan ini adalah bagaimana itu diterapkan. Jelas, _ValueType()
sementara crash stack.
Pertanyaannya adalah apakah itu implementasi yang sesuai. Jika ya, itu sebenarnya berarti penggunaan vektor tipe besar sangat terbatas, bukan?
std::allocator
digunakan.Jawaban:
Tidak ada batasan berapa banyak penyimpanan otomatis yang digunakan API std.
Mereka semua bisa membutuhkan ruang penyimpanan 12 terabyte.
Namun, API itu hanya membutuhkan
Cpp17DefaultInsertable
, dan implementasi Anda menciptakan contoh tambahan atas apa yang dibutuhkan oleh konstruktor. Kecuali jika terjaga keamanannya mendeteksi objek itu sepele dan dapat disalin, implementasi itu terlihat ilegal.sumber
std::allocator
digunakan. Saya tidak yakin mengapa kasus khusus ini dibuat sejak awal.std::fill
untuk jenis sepele, yang kemudian digunakanmemcpy
untuk meledakkan byte ke tempat-tempat, yang berpotensi jauh lebih cepat daripada membangun banyak objek individu dalam satu lingkaran. Saya percaya implementasi libstdc ++ sudah sesuai, tetapi menyebabkan stack overflow untuk objek besar adalah bug Kualitas Implementasi (QoI). Saya telah melaporkannya sebagai gcc.gnu.org/PR94540 dan akan memperbaikinya.Saya membantah anggapan "sebagian besar". Karena memori dari objek besar tidak pernah digunakan, kompiler dapat sepenuhnya mengabaikannya dan tidak pernah mengalokasikan memori dalam hal ini tidak akan ada crash.
Standar C ++ tidak membatasi penggunaan stack, atau bahkan mengakui keberadaan stack. Jadi, ya itu sesuai dengan standar. Tetapi orang dapat menganggap ini sebagai kualitas masalah implementasi.
Itu tampaknya menjadi kasus dengan libstdc ++. Kecelakaan itu tidak direproduksi dengan libc ++ (menggunakan dentang), jadi sepertinya ini bukan batasan dalam bahasa, melainkan hanya dalam implementasi tertentu.
sumber
Saya bukan pengacara bahasa atau pakar standar C ++, tetapi cppreference.com mengatakan:
Mungkin saya salah paham "dimasukkan secara default," tetapi saya berharap:
menjadi setara dengan
Versi terakhir seharusnya tidak membuat salinan tumpukan tetapi membangun besar_type langsung di memori dinamis vektor.
Saya tidak dapat secara otoritatif mengatakan bahwa apa yang Anda lihat tidak sesuai, tetapi tentu saja bukan itu yang saya harapkan dari implementasi yang berkualitas.
sumber
std::allocator
, jadi seharusnya tidak ada perbedaan yang dapat diamati antara memasukkan langsung ke memori vektor dan membuat salinan perantara.emplace_back
tetapi tidak hanya membuat vektor. Yang berarti Anda dapat memilikivector<mutex> v(1)
tetapi tidakvector<mutex> v; v.emplace_back();
Untuk sesuatu sepertihuge_type
Anda mungkin masih memiliki alokasi dan memindahkan operasi lebih banyak dengan versi kedua. Seharusnya tidak membuat objek sementara.vector::vector(size_type, Allocator const&)
membutuhkan (Cpp17) DefaultInsertable