Dizi verilerinde değişiklik yapılmasını nasıl önleyebilirim?


9

Diyelim ki böyle bir sınıf var (bu sadece bir örnek):

class A {
    double *ptr;
public:
    A() : ptr( new double[100] ) {}
    A( const A &other ) {
        other.ptr[7] = 15;
    }
    void doNotChangeMyData() const {
        ptr[43] = 14;
    }
    void changeMyData() {
        ptr[43] = 14;
    }
    ~A() { delete[] ptr; }
};

constKopya kurucu ve hem de doNotChangeMyDataböylece fonksiyonu yapmak ptrdeğiştirilemez; ancak bu yine de işaret ettiği dizinin içeriğini değiştirmeme izin veriyor ptr.

Dizisinin içeriğinin yalnızca örnek ptrolarak değiştirilmesini önlemenin, const"dikkatli olmak" (veya ham işaretçiden uzaklaşmak) dışında bir yolu var mı?

Gibi bir şey yapabileceğimi biliyorum

void doNotChangeMyData() const {
    const double *const ptr = this->ptr;
    ptr[43] = 14; // then this would fail to compile
}

Ama yapmak istemem ...


1
kullanabilirsinizstd::vector
idclev 463035818

std::vector::operator[]()değerleri değiştirebilir mi?
marvinIsSacul

@ formerlyknownas_463035818 Düzenlenmiş soru bu yüzden bir seçenek değil;) Bu daha teorik bir soru, ama evet, vectorişe yarayacaktı.
ChrisMM

2
@marvinIsSacul, ancak std::vector::operator[]() constbir constbaşvuru döndürür
idclev 463035818

@ChrisMM beklediğim, sadece odadaki fil bahsetmek istedim :)
idclev 463035818

Yanıtlar:


7

İşaretçiler yayılmaz const. constTip double*verimi eklenirse double* const, constkayıttan çıkarıldığında değer kaybı olmaz.

Bunun yerine aşağıdakileri kullanabilirsiniz std::vector:

class A {
    std::vector<double> data(100);
public:
    // no explicit copy ctor or dtor
};

a std::array:

class A {
    std::array<double, 100> data{};
public:
    // no explicit copy ctor or dtor
};

veya yerleşik bir dizi (önerilmez):

class A {
    double data[100] {};
public:
    // no explicit copy ctor or dtor
};

Üç seçeneğin tümü yayılır const.

Eğer varsa gerçekten (kuvvetle tavsiye edilmez) işaretçileri kullanmak istiyorum, en azından bir kullanma std::unique_ptrkılavuzu bellek yönetimini önlemek için. Sen kullanabilirsiniz std::experimental::propagate_constkütüphane temelleri 2 TS üzerindeki kağıdı:

class A {
    std::experimental::propagate_const<std::unique_ptr<double[]>> ptr;
public:
    A()
        : ptr{new double[100] {}}
    {
    }
    // manual copy ctor
    A(const A& other)
        : ptr{new double[100]}
    {
        std::copy_n(other.ptr.get(), 100, ptr.get());
    }
    // defaulted move ctor & dtor
    // assignment operator, etc.
    // ...
};

Henüz standartta değil, ancak birçok derleyici bunu destekliyor. Tabii ki, bu yaklaşım uygun kaplardan daha düşüktür.


temel veri türünü değiştirmeden bunu yapmaya çalışmak, her şeyden çok teorik bir soru. Mümkünse, mümkün olmadığında kabul edeceğim.
ChrisMM

@ChrisMM Cevabı işaretçi bir çözümle güncelledim. Ama neden :)
LF

"Neden" cevaplamak zor, daha çok bir merak. std::arrayDerleme zamanında boyutu bilmiyorsanız "Yerleşik dizi" veya çalışmıyor. vectorek yük ekler; unique_ptrek yük eklemez, ancak işaretçinin paylaşılması gerekiyorsa shared_ptr, ek yük ekler. VS şu anda destekliyor sanmıyorum propagate_const(en azından cppreference tarafından belirtilen başlık dosyası ile mevcut değil /std:c++latest) :(
ChrisMM

1
@ChrisMM vectorÖzellikle manuel bellek yönetiminin çabasıyla karşılaştırıldığında genel giderleri TBH'nin üzerinde olduğundan fazla tahmin ediliyor. Ayrıca, işaretçileri elle paylaşırsanız, bir referans sayımı kullanmanız gerekir, bu nedenle ek yüke özgü değildir shared_ptr. propagate_constVS'nin henüz desteklemediğini bilmiyordum (GCC ve Clang, her ikisini de IIRC'yi destekliyor), ancak spesifikasyonlara göre kendimizi yaymak zor değil.
LF

Yükün minimum düzeyde olduğunu kabul ediyorum, ancak performans kritik olduğunda (bellek ve zaman) ham işaretçiler kullanmanın nedenleri var. Bazen bir veya vectordaha sonra içeriğini .data()veya aracılığıyla almak ve &vec[0]bunun yerine doğrudan çalışıyorum. Paylaşılan durumda, genellikle işaretçiyi oluşturan ve silen bir sahibim var, ancak diğer sınıflar verileri paylaşıyor.
ChrisMM
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.