2

I am trying to implement my own std::vector container, and I am using realloc() to resize it, to prevent deletion and reallocation every time. With the following code:

buffer = new T[n]();

This would default initialize each element of the array, and allow me to start accessing them right away. However, since the standard specifies that the memory must be previously allocated by malloc(), calloc() or realloc() to use realloc(), I cannot use new.

I know that calloc() will zero-initialize the memory, but I am not sure if that will have the same behavior as new T[n](). What is the proper way to default-intialize with C style memory allocation?

Michael Smith
  • 1,271
  • 1
  • 8
  • 31
  • 1
    "I am not sure if [`calloc()`] will have the same behavior as new T[n]()" Absolutely not. C functions know nothing about the C++ object lifetime model and are not sufficient to create valid C++ objects. IIRC, even for trivially constructable types, debate rages over whether the Standard indicates they can legally begin life via `malloc()` alone. And usually, if there has to be a debate about it, it's not safe to rely on yet. – underscore_d Jan 03 '18 at 16:27
  • "_I know that `calloc()` will zero-initialize the memory, but I am not sure if that will have the same behavior as `new T[n]()`._" One thing that is different is: it won't call constructors. In fact: none of C memory allocation routines will, since, well.. C doesn't have them. – Algirdas Preidžius Jan 03 '18 at 16:29
  • 1
    You can't implement a std::vector like class with realloc. –  Jan 03 '18 at 16:30
  • 2
    @Fureeish The link you provide contradicts your statement. – François Andrieux Jan 03 '18 at 16:32
  • 1
    You can't use `realloc` here unless your objects are trivially copyable. It seems you are severely underestimating the difficulty of the task you set out to complete. – Baum mit Augen Jan 03 '18 at 16:41
  • Agreed with other comments, but still, if you want to try it, the next thing you need to learn is: https://en.wikipedia.org/wiki/Placement_syntax – Jeffrey Jan 03 '18 at 16:43
  • Relevant read: https://stackoverflow.com/q/8003233/3002139 – Baum mit Augen Jan 03 '18 at 16:45

2 Answers2

3

First, no, zero-initializing memory is not the same as calling default constructors for the objects that that memory is supposed to hold. You have to call constructors. So malloc versus calloc doesn't matter in terms of correctness; so if you're going to go that route, use malloc -- it's faster.

Second, realloc won't work directly, because it doesn't know how to copy objects. Some objects can be copied byte-by-byte, and for those types, realloc is okay. But for most types, copying involves additional operations, and you have to use the copy constructor or copy assignment operator to do the copy. So realloc can be used in special cases, but not in general.

So, you're really limited to malloc and free, along with constructors (through placement new) and destructors.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

You can call any constructor with any kind of memory using this syntax:

::new (ptr) T(...arguments go here (if any)...);

You may have to use

#include <new>

It will call the constructor of T for a memory allocated at ptr. for an array you will have to loop:

T* ptr=(T*)malloc(sizeof(T)*n);
for(int i=0;i<n;++i)
   ::new(ptr+i) T();

But with this, DO NOT CALL delete ! You will have to explicitly call the destructor for each item and then free the memory with the correct function:

for(int i=0;i<n;++i)
   (ptr+i)->~T();
free(ptr);

In case of realloc, you must be sure that the T object can be relocated without any problem (byte-to-byte copy OK). It should be safe for struct with simple data type.

Pascal
  • 142
  • 3