allocating memory vs creation

Hello Forum,

As I understand it (please correct me if I am wrong), there is a difference between allocating memory for a variable, and the actual creation of the variable.
"Memory allocation is the process of setting aside sections of memory in a program to be used to store variables, and instances of structures and classes."
Most C++ articles use the word "allocate" for both allocating the memory and creating the variable. Which makes it hard to find information about it.

Are there situations that C++ code only allocates memory and not yet creates the variable? Any pitfalls regarding this subject?

Thank you.
its complex :)

creation of a non-dynamic (not a pointer) plain old variable does one of 2 or 3 things in most cases.
1) it pushes the program stack, which is pre-allocated block of memory that the program owns, so it just grabs the next free chunk of bytes.
2) it just uses a CPU register. Some variables don't need to persist enough for the compiler to bother with making a location for it, eg some loop variables.
3) it does nothing at all. The variable is optimized away entirely.

pointers are different. YOU allocate the memory and YOU give it back to the OS when you are done with it.
int* ip = new int; //by the way, the pointer variable itself (ip) is like the above^, the pointed to 'variable' is what I am talking about here.
*ip = 13;
delete ip;

complex types like string follow the above rules but they CONTAIN their own variables some of which are (often) pointers that follow the second set of rules.
so if you create a string, it goes on the stack as before, but inside it allocates a pointer that you don't know or care about. If that makes sense?

There are no cases I can think of where it allocates memory that isnt immediately usable.
The pointers, you can have the handle without having the memory:
int *ip;
*ip = 13; //uh-oh... you don't have any memory for this entity, and you HOPE it crashes because anything else it does is going to be a lot of trouble to find and fix.

It sounds like you are running into casual use of terminology.
creation of a variable is not memory allocation. The memory is already allocated if any is used.
pointers and objects that contain pointers allocate memory. This is done explicitly in the code.
Last edited on
Are there situations that C++ code only allocates memory and not yet creates the variable?

Yes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>

struct Complex
{
  double example;

  Complex() {
    std::cout << "==Complex ctor\n";
  }
};

int main()
{
  std::vector<Complex> space;
  std::cout << "int\t" << sizeof(int) << '\n';
  space.reserve( 1000 );
  std::cout << "double\t" << sizeof(double) << '\n';
  space.resize( 2 );
  std::cout << "Complex\t" << sizeof(Complex) << '\n';
  std::cout << "space\t" << sizeof(space) << '\n';
  std::cout << "size\t" << space.size() << '\n';
  std::cout << "capacity\t" << space.capacity() << '\n';
}

Example output:
int	4
double	8
==Complex ctor
==Complex ctor
Complex	8
space	24
size	2
capacity	1000

Line 15: We create empty vector 'space'. No Complex is created.

Line 16: In the test system integer variable would need 4 bytes.

Line 17: The space allocates memory for 1000 Complex, yet none are created.

Line 18: In the test system double variable would need 8 bytes.

Line 19: The space actually creates 2 Complex objects and we see message from their constructors.

Line 19: In the test system a Complex variable needs 8 bytes (for it contains a double member 'example'). 1000 Complexes require thus a block of 8000 bytes.

Line 20: The vector object uses 24 bytes of stack memory. (Could be pointer, size, and capacity.)

Line 21: The vector does indeed have 2 "created" elements.
Line 22: But it has memory allocated for 1000.


How does the vector do it? I don't really care to know. Fact is that it can.

Can we? There is placement new. See https://en.cppreference.com/w/cpp/language/new
I said: There are no cases I can think of where it allocates memory that isnt immediately usable.
The above post shows that an OBJECT can do this. The object is allocating the memory and blocking the user from getting to it until additional requirements are met. Inside the object, you could access those locations; they exist and you have a handle to them, but the object has rules that it wants you to follow, that you add an item and increment a "got this many" counter etc before admitting that it 'has' it to the user.

This is where the lines get fuzzy. Yes, its allocating some memory that you cannot get to. But its doing so by getter-setter like mechanics where the access to that memory is blocked (private membership) and prevented actively (object's defined rules not met to allow it). The memory is there, and if you could get that private pointer, you could read and write into it .... is this helping or more confusing?

btw it would probably be ok** (in terms of it being an allocated and safe usable location) at line 22 to access vector[20]. The memory is there, and that would get you to it (once there is ONE element in the vector, the rest of the memory is a sequential block so you can offset into it), but its not recognized by the class so its not a good thing to DO that; its not understood in the size() method and its not reachable with automatic for loops etc. You can GET there but doing so is breaking the use of the object and not really safe nor sane to do apart from playing with it to learn a bit about memory magic. if not vector[20] (compiler may be smart about this and complain), &vector[0] fed to a pointer and offset will get there.

** OK meaning its valid memory only.
Not all containers are this nice. Vectors were meant to replace arrays and are assured to be a single block of memory. Other containers may not ensure this and the memory and if they supported a reserve command, you would still not have a clean way to steal the pointer. The memory still exists and all, but you can't get to it as easily as a vector, in other words; its like the vector when NO elements have yet been added, you can't get to the pointer as easily in that case...
Last edited on
There are no cases I can think of where it allocates memory that isnt immediately usable.

cppreference.com has the example about placement new:
1
2
3
4
5
6
7
8
9
10
11
12
char* ptr = new char[sizeof(T)]; // allocate raw memory
// formally, you have an array of char

T* tptr = new(ptr) T;            // construct in allocated storage ("place")
// now you have a properly created T object

// use tptr

// alas, explicit destruction is required
tptr->~T();                      // destruct

delete[] ptr;                    // deallocate raw memory 

Yes, the new [] on line 1 does both allocate memory and "create objects", but those objects are simple char, whose "constructor" (and destructor) is trivial.
Yes, that block memory is immediately usable as array of char.

However, the intent here is not to use an array. The intent is to use a T object. There creation -- proper initialization of T is delayed to line 4. T is a complex object, whose internal state is intricate.
The placement new does not allocate memory. It merely calls the constructor of a class.

We can do it.

The same page refers to class Allocator that encapsulates the use of placement new.
You can give a custom Allocator to std containers. For example, to change how std::vector manages memory.


Why would you do that?

Dynamic memory allocation is relatively slow; the system has to find a suitable block from heap and do accounting. What if you know how you will need memory and allocate a big block for all your needs, once at start of a procedure?

Then use placement new (via allocators) to construct and destruct objects within that block. You obviously have to do the "seek&account" yourself, but IF your use case is clear, then your specific implementation can be more efficient than the generic OS heap.
Thank you for all the information. An interesting topic.
Topic archived. No new replies allowed.