C ++ 'da nasıl yeniden tahsis edersiniz?


87

reallocC ++ 'da nasıl yapabilirim ? Dilde eksik görünüyor - var newve deleteyok resize!

Buna ihtiyacım var çünkü programım daha fazla veri okurken, onu tutmak için tamponu yeniden tahsis etmem gerekiyor. deleteEski işaretçiyi ve newyeni, daha büyük bir işaretçiyi seçmenin doğru seçenek olduğunu düşünmüyorum .


8
Stroustrup uzun zaman önce, bkz bu cevap verdi: www2.research.att.com/~bs/bs_faq2.html#renew (Yani Cline'ı C ++ SSS birlikte C ++ yeniyseniz iyi bir başlangıç.)
dirkgently

9
@Dirkgently tarafından referans verilen cevap şu anda şu adreste: stroustrup.com/bs_faq2.html#renew - ve Cline'ın SSS'si artık süper SSS'nin bir parçası: isocpp.org/faq
maxschlepzig

Yanıtlar:


54

:: std :: vektör kullanın!

Type* t = (Type*)malloc(sizeof(Type)*n) 
memset(t, 0, sizeof(Type)*m)

olur

::std::vector<Type> t(n, 0);

Sonra

t = (Type*)realloc(t, sizeof(Type) * n2);

olur

t.resize(n2);

İşaretçiyi işleve geçirmek yerine

Foo(t)

kullanım

Foo(&t[0])

Bu kesinlikle doğru C ++ kodudur, çünkü vektör akıllı bir C dizisidir.


1
Memset satırı memset (t, 0, sizeof (T) * n); m yerine n?
Raphael Mayer

1
@anthom evet. gerçekten olmalıType* t = static_cast<Type*>(malloc(n * sizeof *t));
Ryan Haining

2
C ++ 11 ile artık t.data()yerine&t[0]
knedlsepp

1
Bunu nasıl silebilirsin?
a3mlord

@ a3mlord: Ne demek istiyorsun? Kapsam dışına çıkmasına izin verin ve gitti.
Orbit'te Hafiflik Yarışları

50

Doğru seçenek muhtemelen işi sizin için yapan bir kap kullanmaktır std::vector.

newve deleteyeniden boyutlandıramazlar, çünkü verilen türde bir nesneyi tutmaya yetecek kadar bellek ayırırlar. Belirli bir türün boyutu asla değişmeyecektir. Vardır new[]ve delete[]ama onları kullanmak için neredeyse hiçbir neden yoktur.

Ne reallocC tıpkı bir olması muhtemeldir malloc, memcpyve freekullanılabilir yeterli bitişik boş bellek varsa hafıza yöneticileri akıllıca bir şey yapmak için izin olmasına rağmen, yine de.


6
@bodacydo: Büyüyen tamponu uygulamayın, sadece kullanın std::vector- gerektiğinde otomatik olarak büyür ve isterseniz belleği önceden tahsis edebilirsiniz ( reserve()).
sharptooth

4
Std :: vector <T> kullanın. Bunun için. C ++ 'da, açıkça kaynak yönetimi sınıfları yazmadığınız sürece, new / delete / new [] / delete []' ı kendinizin kullanması için hiçbir neden yoktur.
Puppy

4
@bod: Evet olabilir. (Bu arada olabilir std::string.)
fredoverflow

1
Evet olabilir, sorun değil. Hattastd::stringBunu yapabilir. Bu arada, veri okumanızın da basitleştirilmesi ihtimali var. Verilerinizi nasıl okuyorsunuz?
Thomas

2
Gibi Sesler thevector.resize(previous_size + incoming_size)ardından bir memcpy(veya benzeri) içine &thevector[previous_size], sen ne gerek. Vektör verilerinin "bir dizi gibi" depolanması garanti edilir.
Thomas

38

C ++ 'da yeniden boyutlandırma, yapıcıları ve yıkıcıları çağırma olasılığından dolayı gariptir.

C ++ ' resize[]da gidecek bir operatörünüzün olmamasının temel bir nedeni olduğunu sanmıyorum new[]ve delete[]bu şuna benzer bir şey yaptı:

newbuf = new Type[newsize];
std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf);
delete[] oldbuf;
return newbuf;

Açıkçası oldsizegizli bir yerden alınacaktı, aynı olduğu gibi delete[]veType işlenen türde gelirdi. resize[]Tür kopyalanamadığında başarısız olur - bu doğrudur, çünkü bu tür nesneler yeniden konumlandırılamaz. Son olarak, yukarıdaki kod, nesneleri atamadan önce varsayılan olarak inşa eder, ki bunu gerçek davranış olarak istemezsiniz.

newsize <= oldsizeYeniden küçültülmüş dizinin "sonunu geçen" nesneler için yıkıcıları çağırmak ve başka hiçbir şey yapmamak için olası bir optimizasyon var . Standart, bu optimizasyonun gerekli olup olmadığını tanımlamalıdır (resize() bir vektörde olduğu gibi), izin verilip verilmediğini, izin verilip verilmediğini, ancak uygulamaya bağlı mı yoksa yasak .

O zaman kendinize sormanız gereken soru, "bunu sağlamak gerçekten yararlı mıdır? vector da yapıyor ve özellikle yeniden boyutlandırılabilir bir kap (bitişik bellek - bu gereksinim C ++ 98'de ihmal edildi, ancak C ++ 03'te düzeltildi) bu, işleri yapmak için C ++ yöntemlerine sahip dizilerden daha uygun mu? "

Bence yanıtın yaygın olarak "hayır" olduğu düşünülüyor. Yeniden boyutlandırılabilir arabellekleri C yolu ile yapmak istiyorsanız malloc / free / realloc, C ++ 'da bulunanları kullanın . Yeniden boyutlandırılabilir arabellekleri C ++ yolu ile yapmak istiyorsanız, bir vektör kullanın (veya dequeaslında bitişik depolamaya ihtiyacınız yoksa). new[]Vektör benzeri bir kap uygulamadığınız sürece, bu ikisini ham tamponlar için kullanarak karıştırmaya çalışmayın .


0

İşte realloc ile basit bir vektör uygulayan bir std :: move örneği (limite her ulaştığımızda * 2). Aşağıdaki kopyadan daha iyisini yapmanın bir yolu varsa lütfen bana bildirin.

Şu şekilde derleyin:

  g++ -std=c++2a -O2 -Wall -pedantic foo.cpp

Kod:

#include <iostream>
#include <algorithm>

template<class T> class MyVector {
private:
    T *data;
    size_t maxlen;
    size_t currlen;
public:
    MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
    MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }

    MyVector<T> (const MyVector& o) {
        std::cout << "copy ctor called" << std::endl;
        data = new T [o.maxlen];
        maxlen = o.maxlen;
        currlen = o.currlen;
        std::copy(o.data, o.data + o.maxlen, data);
    }

    MyVector<T> (const MyVector<T>&& o) {
        std::cout << "move ctor called" << std::endl;
        data = o.data;
        maxlen = o.maxlen;
        currlen = o.currlen;
    }

    void push_back (const T& i) {
        if (currlen >= maxlen) {
            maxlen *= 2;
            auto newdata = new T [maxlen];
            std::copy(data, data + currlen, newdata);
            if (data) {
                delete[] data;
            }
            data = newdata;
        }
        data[currlen++] = i;
    }

    friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
        auto s = o.data;
        auto e = o.data + o.currlen;;
        while (s < e) {
            os << "[" << *s << "]";
            s++;
        }
        return os;
    }
};

int main() {
    auto c = new MyVector<int>(1);
    c->push_back(10);
    c->push_back(11);
}

-7

bunun gibi bir şey dene:

typedef struct Board
{
    string name;
    int size = 0;
};

typedef struct tagRDATA
{
    vector <Board> myBoards(255);

    // Board DataBoard[255];
    int SelectedBoard;

} RUNDATA;

Vektör şikayet edecek. Bu yüzden diziler, malloc ve yeni hala var.


12
Hayır, nedeni bu değil. Ve bunun soruyu nasıl yanıtladığını hiçbir şekilde anlamıyorum. Ya da neden typedefher yerde C yazıyormuşsunuz gibi kullanıyorsunuz
Orbit'te Hafiflik Yarışları
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.