Neden std :: vector'ün veri göstericisini değiştiremiyoruz?

Dec 30 2020

Bir dizim char* sourceve bir vektörüm var std::vector<char> target. Verileri kopyalamadan vektörün O (1) ' targete 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

7 anatolyg Dec 30 2020 at 17:39

C ++ vectorsınıfı, bellekte garantili ardışık sırayla öğe eklemeyi ve silmeyi destekler. Eğer vectormevcut 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

vectorVerilerinizi kopyalayarak (iki assigniş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.

3 NutCracker Dec 30 2020 at 19:23

std::vectortemeldeki 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_viewiç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::spanC ++ 20'den kullanma

std::spanC ++ 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::spanolduğ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 spanyapı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.