Neden std :: vector'ün veri göstericisini değiştiremiyoruz?
Bir dizim char* source
ve bir vektörüm var std::vector<char> target
. Verileri kopyalamadan vektörün O (1) ' target
e gelmesini istiyorum source
.
Bu satırlarda bir şey:
#include <vector>
char* source = new char[3] { 1, 2, 3 };
std::vector<char> target;
target.resize(3);
target.setData(source); // <- Doesn't exist
// OR
std::swap(target.data(), source); // <- swap() does not support char*
delete[] source;
Bir vektörün gösterdiği yeri manuel olarak değiştirmek neden mümkün değil? Bu mümkün olsaydı ortaya çıkabilecek belirli, yönetilemez bir sorun var mı?
Yanıtlar
C ++ vector
sınıfı, bellekte garantili ardışık sırayla öğe eklemeyi ve silmeyi destekler. Eğer vector
mevcut bellek tamponunuzu başlatabilirseniz ve ona yeterli eleman ekleyebilirseniz, bu ya taşar ya da yeniden tahsis gerektirir.
Arayüzü , dahili tamponunu yönettiğinivector
varsayar , yani, istediği zaman tahsis edebilir, ayırabilir, yeniden boyutlandırabilir (tabii ki spesifikasyon dahilinde). Arabelleğini yönetmesine izin verilmeyen bir şeye ihtiyacınız varsa , kullanamazsınız - farklı bir veri yapısı kullanın veya kendiniz bir tane yazın.vector
vector
Verilerinizi kopyalayarak (iki assign
işaretli bir kurucu kullanarak veya ) bir nesne oluşturabilirsiniz , ancak bu kesinlikle istediğiniz şey değildir.
Alternatif olarak, string_viewihtiyacınız olana neredeyse veya belki de tam olarak görünen şeyi kullanabilirsiniz.
std::vector
temeldeki tamponun sahibi olarak kabul edilir. Arabelleği değiştirebilirsiniz, ancak bu değişiklik tahsise neden olur, yani istemediğiniz kaynak arabelleğinin bir kopyasını oluşturur (soruda belirtildiği gibi).
Şunları yapabilirsiniz:
#include <vector>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::vector<char> target;
target.resize(3);
target.assign(source, source + 3);
delete[] source;
return 0;
}
ama yine std::vector::assign:
İçerikleri [birinci, son) aralığındaki kopyalarla değiştirir .
Böylece kopyalama işlemi yeniden gerçekleştirilir. Kullanırken ondan uzaklaşamazsınız std::vector
.
Verileri kopyalamak istemiyorsanız std::span
, C ++ 20'yi kullanmalısınız (veya kendi yayılımınızı oluşturmalısınız) veya kullanmalısınız std::string_view
(bir dizi diziniz olduğu için size uygun görünüyor char
).
1. seçenek: Kullanma std::string_view
C ++ 17 ile sınırlı olduğunuz std::string_view
için sizin için mükemmel olabilir. İşaret ettiği öğeden başlayarak karakter dizisinin ilk 3 karakterinin bir görünümünü oluşturur source
.
#include <iostream>
#include <string_view>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::string_view strv( source, 3 );
delete[] source;
return 0;
}
2. seçenek: std::span
C ++ 20'den kullanma
std::span
C ++ 20'den geliyor, bu yüzden sizin için en mükemmel yol olmayabilir, ancak ne olduğu ve nasıl çalıştığı ile ilgilenebilirsiniz. Sadece karakterlerin değil, her türden nesnelerin bitişik bir dizisi std::span
olduğu için biraz genelleştirilmiş bir versiyon olarak düşünebilirsiniz std::string_view
. Kullanım şununla benzerdir std::string_view
:
#include <span>
#include <iostream>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::span s( source, 3 );
delete[] source;
return 0;
}
3. seçenek: Kendi aralığınız
C ++ 17 ile sınırlıysanız, kendi span
yapınızı oluşturmayı düşünebilirsiniz . Yine de abartılı olabilir ama size göstermeme izin verin (btw bu daha ayrıntılı yanıta bir göz atın ):
template<typename T>
class span {
T* ptr_;
std::size_t len_;
public:
span(T* ptr, std::size_t len) noexcept
: ptr_{ptr}, len_{len}
{}
T& operator[](int i) noexcept {
return *ptr_[i];
}
T const& operator[](int i) const noexcept {
return *ptr_[i];
}
std::size_t size() const noexcept {
return len_;
}
T* begin() noexcept {
return ptr_;
}
T* end() noexcept {
return ptr_ + len_;
}
};
int main() {
char* source = new char[3] { 1, 2, 3 };
span s( source, 3 );
delete[] source;
return 0;
}
Dolayısıyla kullanım, C ++ 20'nin std::span
.