How to Initialise Memory With New Operator in C++

How to initialise memory with new operator in C++?

It's a surprisingly little-known feature of C++ (as evidenced by the fact that no-one has given this as an answer yet), but it actually has special syntax for value-initializing an array:

new int[10]();

Note that you must use the empty parentheses — you cannot, for example, use (0) or anything else (which is why this is only useful for value initialization).

This is explicitly permitted by ISO C++03 5.3.4[expr.new]/15, which says:

A new-expression that creates an object of type T initializes that object as follows:

...

  • If the new-initializer is of the form (), the item is value-initialized (8.5);

and does not restrict the types for which this is allowed, whereas the (expression-list) form is explicitly restricted by further rules in the same section such that it does not allow array types.

Operator new initializes memory to zero

There are two versions:

wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int(); // zero initialized (ie set to 0)

Also works for arrays:

wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero initialized (ie all elements set to 0)

In answer to comment below.

Ehm... are you sure that new unsigned int[5]() zeroes the integers?

Apparently yes:

[C++11: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows: If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed, the object has indeterminate value. Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.

#include <new>
#include <iostream>


int main()
{
unsigned int wsa[5] = {1,2,3,4,5};

// Use placement new (to use a know piece of memory).
// In the way described above.
//
unsigned int* wsp = new (wsa) unsigned int[5]();

std::cout << wsa[0] << "\n"; // If these are zero then it worked as described.
std::cout << wsa[1] << "\n"; // If they contain the numbers 1 - 5 then it failed.
std::cout << wsa[2] << "\n";
std::cout << wsa[3] << "\n";
std::cout << wsa[4] << "\n";
}

Results:

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>

Bulk-allocating objects with calling new operator once?

The emphasis on my question is that memory is only taken from the
kernel once, when I reserve 1200 bytes for 100 X objects. After the
beginning of my program I want the bare minimum to be executed when
retrieving an X object "shell"?

It sounds like what you're trying to do is akin to building a memory pool.

In a memory pool, you pre-allocate a large raw buffer where objects will eventually live. Later you allocate individual objects within this buffer. Doing this has the advantage of not having to allocate memory for each individual object -- all you have to do is construct the object within the pre-allocated space. Since you don't have to go down to the kernel for each Object instantiated this way, there are potentially substantial time savings. The drawback is you are taking responsibility for managing these objects in a more-direct way. The code can be tricky, complex and bug-prone.

To allocate the raw buffer, we simply allocate a char array big enough to hold all the anticipated Objects:

char* buf = new char [1200];

In order to do the second part -- constructing an object within the memory pool -- you need to use placement-new. Assuming buf is the location in the pre-allocated buffer where you want your new object p to be constructed:

Object* p = new (buf) Object();

When it comes time to destroy this object, do not use delete. delete will attempt to deallocate the memory for the object, yielding undefined behavior and a likely crash since you didn't allocate the memory for the object1. Instead, this is one case where you must call the destructor directly:

p->~Object();

Once all the objects have been destroyed, you can then release the buffer using delete[]:

delete [] buf;

Here is a complete example showing how to use placement-new, including construction of the buffer. This uses the (implicitly defined) default constructor. I'll show how to use another constructor later:

#include <cstdlib>
#include <new> // required for placement-new
#include <iostream>


class X
{
public:
int a;
long b;
float c;
};

int main()
{
// construct the memory pool's buffer
char* buf = new char [sizeof(X) * 1000]; // enough memory for 1000 instances of X

// Instantiate 1000 instances of X using placement-new
for (size_t i = 0; i < 1000; ++i)
{
// Where in the memory pool shoudl we put this?
char* buf_loc = buf + (sizeof(X) * i);
// Construct a new X at buf_loc
X* new_x = new (buf_loc) X;
}


// Do something with those instances
for (size_t i = 0; i < 1000; ++i)
{
// Where is the object?
char* buf_loc = buf + (sizeof(X) * i);
X* my_x = reinterpret_cast <X*> (buf_loc); // this cast is safe because I *know* that buf_loc points to an X

// Let's assign some values and dump them to screen
my_x->a = i;
my_x->b = 420000 + i;
my_x->c = static_cast <float> (i) + 0.42;

std::cout << "[" << i << "]\t" << my_x->a << "\t" << my_x->b << "\t" << my_x->c << "\n";
}

// Destroy the X's
for (size_t i = 0; i < 1000; ++i)
{
// Where is the object?
char* buf_loc = buf + (sizeof(X) * i);
X* my_x = reinterpret_cast <X*> (buf_loc); // this cast is safe because I *know* that buf_loc points to an X

// Destroy it
my_x->~X();
}

// Delete the memory pool
delete [] buf;
}

Now let's define a constructor for X which takes arguments:

class X
{
public:
X (int aa, long bb, float cc)
:
a (aa),
b (bb),
c (cc)
{
}
int a;
long b;
float c;
};

Since we've defined a constructor here, the compiler will no longer implicitly define a default constructor for X.

Let's use this new constructor. The arguments to the constructor must now be passed:

   // Instantiate 1000 instances of X using placement-new
for (size_t i = 0; i < 1000; ++i)
{
// Where in the memory pool shoudl we put this?
char* buf_loc = buf + (sizeof(X) * i);
// Construct a new X at buf_loc
X* new_x = new (buf_loc) X(0,0,0.0f);
}

Do not use delete1: Technically, the reason that using delete here yields undefined behavior is because delete can only be called with a pointer that was returned from a call to new. Since you didn't new the object, but placement-newed the object, you cannot call delete.

Initializing an object with and without new operator

Rectangle *Obj;

just defines a pointer to an object of class Rectangle. Defining a pointer does not reserve any memory for the object itself, just for the pointer. Thus, if you access the pointer, you will likely end up at an address in memory that doesn't even belong to your process. However, the compiler cannot know that you haven't initialized the pointer (the keyword here is aliasing) and hence cannot output an error message.

The solution is either using new like you suggested, or declare an instance of Rectangle like so:

Rectangle Obj;

which will call a default constructor. You can then set your members using

Obj.Set(3, 5);

How do you safely clear an object from memory (with attributes) which was created using the new keyword?

Yes. When you delete b it deletes also letters_in_box array.

But, for your b->letters_in_box = "Hello world"; you will get a compile error: "error C3863: array type 'char [80]' is not assignable"

#include <memory> // For 'memcpy_s' (since C11)

class Box
{
public:
double length;
char letters_in_box[80];
};

int main()
{
Box* b = new Box;

b->length = 2.0;
// b->letters_in_box = "Hello world"; ** Compile Error C3863: array type 'char [80]' is not assignable **
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), "Hello world", sizeof("Hello world"));

// Some code with b

delete b;
}

MODERN C++

A better practice than new is smart pointers, than for example you don't have to bother with delete in case of exception and at all:

#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'

class Box
{
public:
double length;
char letters_in_box[80];
};

constexpr char my_text[] = "Hello world";

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), my_text, sizeof(my_text));

// Some code with b
}

Also, (instead of C array) I prefer to use C++ array:

#include <array>  // For 'std::array'
#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'

class Box
{
public:
double length;
std::array<char, 80> letters_in_box;
};

constexpr char my_text[] = "Hello world";

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
memcpy_s(&b->letters_in_box, b->letters_in_box.size(), my_text, sizeof(my_text));

//Some code with b
}

--

One last comment: Without a constraint to use char[], I would use std::string instead:

#include <string> // For 'std::string'
#include <memory> // For 'std::unique_ptr'

class Box
{
public:
double length;
std::string letters_in_box;
};

int main()
{
auto b = std::make_unique<Box>(); // No need to delete

b->length = 2.0;
b->letters_in_box = "Hello world";

//Some code with b
}


Related Topics



Leave a reply



Submit