views:

229

answers:

3

Any ideas how to realloc in C++?

It seems to be the missing language language - there is new and delete but not resize!

I need it because as my program reads more data, I need to reallocate the buffer to hold it.

I don't think deleteing the old pointer and newing a new, bigger one, is the right option. Please enlighten me.

Thanks, Boda Cydo.

+16  A: 

The right option is probably to use a container that does the work for you, like std::vector.

new and delete cannot resize, because they allocate just enough memory to hold an object of the given type. The size of a given type will never change. There are new[] and delete[] but there's hardly ever a reason to use them.

What realloc does in C is likely to be just a malloc, memcpy and free, anyway, although memory managers are allowed to do something clever if there is enough contiguous free memory available.

Thomas
So what would be the right way to implement a growing buffer in C++? Currently I have `char *buf = (char *)malloc(size)`, then when it becomes too small I do `buf = realloc(size + more_size); size += more_size`. How can I do it with vector?
bodacydo
@bodacydo: Don't implement the growing buffer, just use `std::vector` - it will grow automatically when needed and you can pre-allocate memory if you want (`reserve()`).
sharptooth
Use std::vector<T>. That's what it's for. In C++, there is no reason whatsoever to use new/delete/new[]/delete[] yourself, unless you're explicitly writing resource management classes.
DeadMG
So should I use `std::vector<char>`? I am curious if `std::vector<char>` can contain `0` (NUL) bytes?
bodacydo
@bod: Yes, it can. (So can `std::string`, by the way.)
FredOverflow
Yes, it can, no problem. Even `std::string` can do that. By the way, there's a chance that your data reading can be simplified, too. How are you reading your data?
Thomas
Thomas: the data comes in from the network, and I don't really have control over how much of it is gonna come in. It works like this - a packet comes in and says 100 bytes are following. So I allocate 100 bytes, then there are several types of packets, one might say "200 more bytes", so I do realloc and size += 200.
bodacydo
Thomas
+1; I'd remove "probably" from the first line.
Mike Seymour
Thomas. I just wrote my code with `push_back` and it didn't work. Thanks for explaining the .resize() followed by memcpy.
bodacydo
@bodacydo: Read the docs. The `v.push_back(d)` is semantically equivalent to `v.resize(v.size()+1); v.back() = d;` That will allocate an extra element in the array and insert the data in that position.
David Rodríguez - dribeas
@dribeas: Better than that; `v.push_back(d)` is semantically equivalent to `v.resize(v.size() + 1, d)`; there's no requirement for a default constructed temporary or an assignment operation.
Charles Bailey
+3  A: 

Use ::std::vector!

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

becomes

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

Then

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

becomes

t.resize(n2);

If you want to pass pointer into function, instead of

Foo(t)

use

Foo(&t[0])

It it absolutely correct c++ code, because vector is a smart c-array.

f0b0s
+1  A: 

Resizing in C++ is awkward because of the potential need to call constructors and destructors.

I don't think there's a fundamental reason why in C++ you couldn't have a resize[] operator to go with new[] and delete[], that did something similar to this:

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

Obviously oldsize would be retrieved from a secret location, same is it is in delete[], and Type would come from the type of the operand. resize[] would fail where the Type is not copyable - which is correct, since such objects simply cannot be relocated. Finally, the above code default-constructs the objects before assigning them, which you would not want as the actual behaviour.

There's a possible optimisation where newsize <= oldsize, to call destructors for the objects "past the end" of the newly-ensmallened array and do nothing else. The standard would have to define whether this optimisation is required (as when you resize() a vector), permitted but unspecified, permitted but implementation-dependent, or forbidden.

The question you should then ask yourself is, "is it actually useful to provide this, given that vector also does it, and is designed specifically to provide a resize-able container (of contiguous memory--that requirement omitted in C++98 but fixed in C++03) that's a better fit than arrays with the C++ ways of doing things?"

I think the answer is widely thought to be "no". If you want to do resizeable buffers the C way, use malloc / free / realloc, which are available in C++. If you want to do resizeable buffers the C++ way, use a vector (or deque, if you don't actually need contiguous storage). Don't try to mix the two by using new[] for raw buffers, unless you're implementing a vector-like container.

Steve Jessop