Jak mogę realloc
w C ++? Wydaje się, że brakuje tego języka - jest new
i delete
ale nie ma resize
!
Potrzebuję tego, ponieważ ponieważ mój program odczytuje więcej danych, muszę ponownie przydzielić bufor, aby go przechowywać. Myślę, że delete
stary wskaźnik i new
nowy, większy, nie są właściwą opcją.
c++
new-operator
realloc
delete-operator
bodacydo
źródło
źródło
Odpowiedzi:
Użyj :: std :: vector!
Type* t = (Type*)malloc(sizeof(Type)*n) memset(t, 0, sizeof(Type)*m)
staje się
::std::vector<Type> t(n, 0);
Następnie
t = (Type*)realloc(t, sizeof(Type) * n2);
staje się
Jeśli chcesz przekazać wskaźnik do funkcji, zamiast
posługiwać się
Foo(&t[0])
Jest to absolutnie poprawny kod w C ++, ponieważ wektor jest inteligentną tablicą C.
źródło
Type* t = static_cast<Type*>(malloc(n * sizeof *t));
t.data()
zamiast&t[0]
Prawdopodobnie właściwą opcją jest użycie kontenera, który wykona pracę za Ciebie, na przykład
std::vector
.new
idelete
nie mogą zmienić rozmiaru, ponieważ przydzielają wystarczającą ilość pamięci, aby pomieścić obiekt danego typu. Rozmiar danego typu nigdy się nie zmieni. Sąnew[]
idelete[]
ale prawie nigdy nie ma powodu, aby z nich korzystać.To, co
realloc
robi w C, prawdopodobnie będzie po prostumalloc
,memcpy
ifree
tak czy inaczej, chociaż menedżerowie pamięci mogą zrobić coś sprytnego, jeśli jest wystarczająco dużo dostępnej ciągłej wolnej pamięci.źródło
std::vector
- będzie on wzrastał automatycznie, gdy zajdzie taka potrzeba i możesz wstępnie przydzielić pamięć, jeśli chcesz (reserve()
).std::string
przy okazji.)std::string
może to zrobić. Nawiasem mówiąc, jest szansa, że odczyt danych również może zostać uproszczony. Jak czytasz swoje dane?thevector.resize(previous_size + incoming_size)
, a po nimmemcpy
(lub podobny) do&thevector[previous_size]
, jest to, czego potrzebujesz. Dane wektora są przechowywane „jak tablica”.Zmiana rozmiaru w C ++ jest niewygodna ze względu na potencjalną potrzebę wywoływania konstruktorów i destruktorów.
Nie sądzę, aby istniał podstawowy powód, dla którego w C ++ nie można było mieć
resize[]
operatoranew[]
adelete[]
to zrobiło coś podobnego do tego:newbuf = new Type[newsize]; std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf); delete[] oldbuf; return newbuf;
Oczywiście
oldsize
zostałby pobrany z tajnego miejsca, w którym się znajdujedelete[]
, iType
pochodziłby z typu operandu.resize[]
nie powiedzie się, gdy Typ nie jest kopiowalny - co jest poprawne, ponieważ takich obiektów po prostu nie można przenieść. Na koniec powyższy kod domyślnie konstruuje obiekty przed ich przypisaniem, czego nie chcesz, ponieważ jest to rzeczywiste zachowanie.Możliwa jest optymalizacja, w której
newsize <= oldsize
polegająca na wywołaniu destruktorów obiektów „poza końcem” nowo utworzonej tablicy i nic więcej. Standard musiałby zdefiniować, czy ta optymalizacja jest wymagana (jak w przypadkuresize()
wektora), dozwolona, ale nieokreślona, dozwolona, ale zależna od implementacji, czy zabroniona.Pytanie, które powinieneś sobie wtedy zadać, brzmi: „czy rzeczywiście warto to zapewnić, biorąc pod uwagę, że
vector
również to robi, i jest zaprojektowany specjalnie w celu zapewnienia kontenera z możliwością zmiany rozmiaru (ciągłej pamięci - to wymaganie zostało pominięte w C ++ 98, ale poprawione w C ++ 03), które są lepsze niż tablice ze sposobami robienia rzeczy w C ++? ”Myślę, że powszechnie uważa się, że odpowiedź brzmi „nie”. Jeśli chcesz robić bufory o zmiennym rozmiarze na sposób C, użyj
malloc / free / realloc
, które są dostępne w C ++. Jeśli chcesz tworzyć bufory o zmiennym rozmiarze w sposób C ++, użyj wektora (lubdeque
, jeśli w rzeczywistości nie potrzebujesz ciągłego przechowywania). Nie próbuj mieszać tych dwóch, używającnew[]
dla surowych buforów, chyba że implementujesz kontener podobny do wektora.źródło
Oto przykład std :: move implementujący prosty wektor z realloc (* 2 za każdym razem, gdy osiągniemy limit). Jeśli istnieje sposób, aby zrobić coś lepszego niż kopia, którą mam poniżej, daj mi znać.
Kompiluj jako:
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); }
źródło
spróbuj czegoś takiego:
typedef struct Board { string name; int size = 0; }; typedef struct tagRDATA { vector <Board> myBoards(255); // Board DataBoard[255]; int SelectedBoard; } RUNDATA;
Wektor będzie narzekać. Dlatego nadal istnieją tablice, malloc i new.
źródło
typedef
wszędzie tak, jakbyś pisał C.