Dynamic Memory (Pt.3)
C. Papachristos
Robotic Workers Lab
University of Nevada, Reno
CS-202
Course , Projects , Labs:
Your 7th Project Deadline is this Wednesday 4/1.
Monday | Tuesday | Wednesday | Thursday | Friday | | Sunday |
|
|
| Lab (8 Sections) |
| | |
| CLASS | PASS Session | CLASS |
| | |
PASS Session | | Project DEADLINE | NEW Project | PASS Session | | PASS Session |
Course Week
CS-202 C. Papachristos
Today’s Topics
CS-202 C. Papachristos
Overloading operator new ([]) and operator delete ([])
Storage and Alignment
Alignment and Dynamic Memory
Placement new ([]) ( and Placement delete ([]) ).
Dynamic Memory Allocation
CS-202 C. Papachristos
Remember: The Basics
There is no named Object / Variable : All work is done on a Pointer-basis.
All facilitated by the “behind-the-scenes” use of C++ Dynamic Memory (De-)Allocation functions:
Operator new dynamically Allocates memory space.
void * operator new (std::size_t count);
void * operator new [] (std::size_t count);
Operator delete can free-up this space (Deallocate memory) later on.
void operator delete (void * ptr);
void operator delete [] (void * ptr);
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What if we want to implement our own special low-level memory management ?
They can be overloaded:
Affecting Dynamic Memory Management across our entire program.
Affecting the Dynamic Memory Management pertaining to that particular Class.
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * operator new ([]) (std::size_t count);
void operator delete ([]) (void * ptr);
a) Globally :
#include <iostream>
#include <cstdlib>
using namespace std;
void * operator new(std::size_t size) {
cout<<"Dyn.Alloc. Object of size: "<< size <<endl;
void * p = malloc(size);
if (p == nullptr) {
cout<<"Dyn.Alloc. failed, throwing..."<<endl;
throw std::bad_alloc();
}
return p;
}
Size of requested dynamic memory
Pointer to successfully allocated memory
Pointer of dynamic memory to release
void * operator new [](std::size_t size) {
cout<<"Dyn.Alloc. Object Array of size: "<< size <<endl;
void * p = malloc(size);
if (p == nullptr) {
cout<<"Dyn.Alloc. failed, throwing..."<<endl;
throw std::bad_alloc();
}
return p;
}
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * operator new ([]) (std::size_t count);
void operator delete ([]) (void * ptr);
a) Globally :
#include <iostream>
#include <cstdlib>
using namespace std;
void operator delete(void * ptr) {
cout<<"Dyn.Dealloc. Object at address: "<< ptr <<endl;
if (ptr == (void *)0xDEADBEEF) {
cout<<"CAUTION: delete called on dead pointer"<<endl;
}
else {
free(ptr);
}
}
Size of requested dynamic memory
Pointer to successfully allocated memory
Pointer of dynamic memory to release
void operator delete [](void * ptr) {
cout<<"Dyn.Dealloc. Object Array at address: "<< ptr <<endl;
if (ptr == (void *)0xDEADBEEF) {
cout<<"CAUTION: delete [] called on dead pointer"<<endl;
}
else {
free(ptr);
}
}
Note: Function takes the Pointer by-Value, you cannot reassign its value internally and have the change persist.�(i.e., you can’t do ptr = nullptr; to automatically handled all released memory pointers)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
a) Globally :
#include <iostream>
#include <cstdlib>
using namespace std;
void * operator new(std::size_t size) { … }
void * operator new [](std::size_t size) { … }
void operator delete(void * p) { … }
void operator delete [](void * p) { … }
int main() {
MyStruct * p_ms = new MyStruct(1, 0.1);
cout<<"(*p_ms).a,b : "<<p_ms->a<<","<<p_ms->b<<endl;
delete p_ms;
int * p_i = new int(1);
cout<<"*p_i : "<< *p_i <<endl;
delete p_i; p_i = (int *)0xDEADBEEF; delete p_i;
int * pa_i;
try { pa_i = new int[2305843009213693950]; }
catch (const std::bad_alloc & e) {
pa_i = nullptr;
cout<< e.what() <<endl;
}
delete [] pa_i;
}
struct MyStruct {
MyStruct(int a_in, double b_in) : a(a_in) , b(b_in) { }
int a;
double b;
double c[10];
};
Dyn.Alloc. Object of size: 96
(*p_ms).a,b : 1, 0.1
Dyn.Dealloc. Object at address: 0x800012930
1)
2)
3)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
a) Globally :
#include <iostream>
#include <cstdlib>
using namespace std;
void * operator new(std::size_t size) { … }
void * operator new [](std::size_t size) { … }
void operator delete(void * p) { … }
void operator delete [](void * p) { … }
int main() {
MyStruct * p_ms = new MyStruct(1, 0.1);
cout<<"(*p_ms).a,b : "<<p_ms->a<<","<<p_ms->b<<endl;
delete p_ms;
int * p_i = new int(1);
cout<<"*p_i : "<< *p_i <<endl;
delete p_i; p_i = (int *)0xDEADBEEF; delete p_i;
int * pa_i;
try { pa_i = new int[2305843009213693950]; }
catch (const std::bad_alloc & e) {
pa_i = nullptr;
cout<< e.what() <<endl;
}
delete [] pa_i;
}
struct MyStruct {
MyStruct(int a_in, double b_in) : a(a_in) , b(b_in) { }
int a;
double b;
double c[10];
};
Dyn.Alloc. Object of size: 4
*p_i : 1
Dyn.Dealloc. Object at address: 0x8000004b0
Dyn.Dealloc. Object at address: 0xdeadbeef
CAUTION: delete called on dead pointer
1)
2)
3)
4)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
a) Globally :
#include <iostream>
#include <cstdlib>
using namespace std;
void * operator new(std::size_t size) { … }
void * operator new [](std::size_t size) { … }
void operator delete(void * p) { … }
void operator delete [](void * p) { … }
int main() {
MyStruct * p_ms = new MyStruct(1, 0.1);
cout<<"(*p_ms).a,b : "<<p_ms->a<<","<<p_ms->b<<endl;
delete p_ms;
int * p_i = new int(1);
cout<<"*p_i : "<< *p_i <<endl;
delete p_i; p_i = (int *)0xDEADBEEF; delete p_i;
int * pa_i;
try { pa_i = new int[2305843009213693950]; }
catch (const std::bad_alloc & e) {
pa_i = nullptr;
cout<< e.what() <<endl;
}
delete [] pa_i;
}
struct MyStruct {
MyStruct(int a_in, double b_in) : a(a_in) , b(b_in) { }
int a;
double b;
double c[10];
};
Dyn.Alloc. Object Array of size: 9223372036854775800
Dyn.Alloc. failed, throwing...
std::bad_alloc
1)
2)
3)
? Why is there no output here even though we delete [] ?
We invoked the delete [] Expression on a “Null Pointer”,�which does not call the function operator delete [] !
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * Car :: operator new ([]) (std::size_t count);
void Car :: operator delete ([]) (void * ptr);
b) As static Class Methods :
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() { cout<<"Car Default"<<endl; } ...
void * operator new(std::size_t size) {
cout<<"Dyn.Alloc. Car Object of size: "<< size <<endl;
void * p = malloc(size);
if (p == nullptr) {
cout<<"Dyn.Alloc. failed, throwing..."<<endl;
throw std::bad_alloc();
}
return p;
}
};
Declared within the scope of a Class
void * operator new [](std::size_t size) {
cout<<"Dyn.Alloc. Car Object Array of size: "<< size <<endl;
void * p = malloc(size);
if (p == nullptr) {
cout<<"Dyn.Alloc. failed, throwing..."<<endl;
throw std::bad_alloc();
}
return p;
}
IMPORTANT Note:�As class overloads, they will be implicitly declared static !�(whether you do so or not …)
i)
i)
Provide your own highly customized low-level Dynamic Memory Management for your class.
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * Car :: operator new ([]) (std::size_t count);
void Car :: operator delete ([]) (void * ptr);
b) As static Class Methods :
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() { cout<<"Car Default"<<endl; } ...
void * operator new(std::size_t size) {
cout<<"Dyn.Alloc. Car Object of size: "<< size <<endl;
void * p = ::operator new(size);
return p;
}
};
Declared within the scope of a Class
void * operator new [](std::size_t size) {
cout<<"Dyn.Alloc. Car Object Array of size: "<< size <<endl;
void * p = ::operator new [](size);
return p;
}
IMPORTANT Note:�As class overloads, they will be implicitly declared static !�(whether you do so or not …)
Re-use the global C++ Dynamic Memory Allocation function ( ::f qualifies the name f in the Global Namespace) �Note 1: You might have overloaded the Global one as well.
Note 2: The default operator new ([]) is expected to throw.
ii)
ii)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * Car :: operator new ([]) (std::size_t count);
void Car :: operator delete ([]) (void * ptr);
b) As static Class Methods :
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() { cout<<"Car Default"<<endl; } ...
void * operator new(std::size_t size) {
cout<<"Dyn.Alloc. Car Object of size: "<< size <<endl;
void * p = ::new Car;
return p;
}
};
Declared within the scope of a Class
void * operator new [](std::size_t size) {
cout<<"Dyn.Alloc. Car Object Array of size: "<< size <<endl;
void * p = ::new Car[ size / sizeof(Car) ];
return p;
}
IMPORTANT Note:�As class overloads, they will be implicitly declared static !�(whether you do so or not …)
Re-use the global new ([]) Expression ( ::f qualifies the name f in the Global Namespace) �
Bad Design, something like: Car * c_pt = new Car; will end up calling a ctor twice per Object,�as a side-effect of executing 2 subsequent new ([]) Expressions !
iii)
iii)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Breakdown:
void * Car :: operator new ([]) (std::size_t count);
void Car :: operator delete ([]) (void * ptr);
b) As static Class Methods :
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() { cout<<"Car Default"<<endl; } ...
void operator delete(void * ptr) {
cout<<"Dyn.Dealloc. Car Object at address: "<<ptr<<endl;
::delete ptr;
::operator delete(size);
if (ptr == (void *)0xDEADBEEF)
cout<<"CAUTION: delete called on dead ptr"<<endl;
else
free(ptr);
}
};
Declared within the scope of a Class
void operator delete [](void * ptr) {
cout<<"Dyn.Alloc. Car Object Array at address: "<<ptr<<endl;
::delete [] ptr;
::operator delete [](ptr);
if (ptr == (void *)0xDEADBEEF)
cout<<"CAUTION: delete [] called on dead ptr"<<endl;
else
free(ptr);
}
IMPORTANT Note:�As class overloads, they will be implicitly declared static !�(whether you do so or not …)
i)
iii)
ii)
i)
iii)
ii)
Similarly as before for sample implementations i) ii) iii)
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
b) As static Class Methods :
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
Car * p_c = new Car(1000.0);
cout << "(*p_c).getPrice() : " <<
p_c->getPrice() << endl;
delete p_c;
p_c = (Car *)0xDEADBEEF;
Car * pa_c = new Car[10];
cout << "pa_c[9].getPrice() : " <<
pa_c[9].getPrice() << endl;
delete [] pa_c;
p_ac = (Car *)0xDEADBEEF;
return 0;
}
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { …(i)… }
void * operator new [](std::size_t size) { …(i)… }
void operator delete(void * p) { …(i)… }
void operator delete [](void * p) { …(i)… }
};
Dyn.Alloc. Car Object of size: 24
Car Param
(*p_c).getPrice() : 1000
Car Destructor
Dyn.Dealloc. Car Object at address: 0x8000004b0
1)
2)
3)
...
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
b) As static Class Methods :
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
Car * p_c = new Car(1000.0);
cout << "(*p_c).getPrice() : " <<
p_c->getPrice() << endl;
delete p_c;
p_c = (Car *)0xDEADBEEF;
Car * pa_c = new Car[10];
cout << "pa_c[9].getPrice() : " <<
pa_c[9].getPrice() << endl;
delete [] pa_c;
p_ac = (Car *)0xDEADBEEF;
return 0;
}
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { …(i)… }
void * operator new [](std::size_t size) { …(i)… }
void operator delete(void * p) { …(i)… }
void operator delete [](void * p) { …(i)… }
};
Dyn.Alloc. Car Object Array of size: 248
Car Default (x10)
pa_c[9].getPrice() : 1.34497e-284
Car Destructor (x10)
Dyn.Alloc. Car Object Array at address: 0x80005ac70
1)
2)
3)
...
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { … void * p = malloc(size); … }
void * operator new [](std::size_t size) { … void * p = malloc(size); … }
void operator delete(void * p) { … free(p); … }
void operator delete [](void * p) { … free(p); … }
};
Dyn.Alloc. Car Object of size: 24
...
But the memory footprint should be 18 :
1 x sizeof(double) + 10 x sizeof(char)
double m_price; char m_licensePlates[10];
Right?
Dyn.Alloc. Car Object Array of size: 248
But the memory footprint should be 240 :
… = new Car[10];
Right?
Explanation :
The only reasonable way to expect the program during�runtime to know there is an array of a certain size there, is to�store extra information !
Extra Note :
If we had no user-declared dtor, then the size would be 240, as the�Car object being a data-only (1 double + 10 chars) structure means�the Deallocation of this memory wouldn’t need to do anything about their destruction (even for 10 x Cars).
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { … void * p = malloc(size); … }
void * operator new [](std::size_t size) { … void * p = malloc(size); … }
void operator delete(void * p) { … free(p); … }
void operator delete [](void * p) { … free(p); … }
};
...
Dyn.Alloc. Car Object Array of size: 248
Actually has memory footprint:
8 bytes | 24 bytes | 24 bytes | ... | 24 bytes | 24 bytes |
| | | | | |
Car [10]
how big?
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
class Car {
private: double m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { … void * p = malloc(size); … }
void * operator new [](std::size_t size) { … void * p = malloc(size); … }
void operator delete(void * p) { … free(p); … }
void operator delete [](void * p) { … free(p); … }
};
Dyn.Alloc. Car Object of size: 24
...
Actually requires memory layout:
8 bytes | 8 bytes | 8 bytes |
| | |
Explanation :
The compiler “pads” the memory of our class / struct members to make the object aligned to 8-byte boundaries.
Extra Info :
sizeof( Car ); 24:A Car object takes up 24 bytes
alignof( Car ); 8 :Car objects are placed at 8-byte boundaries
double�m_price;
char�m_licesePlates[10]
Padding
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
class Car {
private: float m_price; char m_licensePlates[10];
public: Car() {cout<<"Car Default"<<endl;}
Car(double price) : m_price(price) {cout<<"Car Param"<<endl;}
~Car() {cout<<"Car Destructor"<<endl;}
void * operator new(std::size_t size) { … void * p = malloc(size); … }
void * operator new [](std::size_t size) { … void * p = malloc(size); … }
void operator delete(void * p) { … free(p); … }
void operator delete [](void * p) { … free(p); … }
};
Dyn.Alloc. Car Object of size: 16
...
Changing double→float requires memory layout:
4 bytes | 4 bytes | 4 bytes | 4 bytes |
| | | |
float�m_price
char�m_licesePlates[10]
Padding
Explanation :
The compiler “pads” the memory of our class / struct members to make the object aligned to 4-byte boundaries.
Extra Info :
sizeof( Car ); 16:A Car object takes up 16 bytes
alignof( Car ); 4 :Car objects are placed at 4-byte boundaries
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
Even more interestingly …
struct S1 {
char c1;
double d;
char c2;
};
alignof(S1):8
sizeof(S1) :24
Based on the structure:
1 char → 1 byte + 7 padding
1 double → 8 bytes
1 char → 1 byte + 7 padding
struct S2 {
char c1;
char c2;
double d;
};
alignof(S2):8
sizeof(S2) :16
Based on the structure:
2 chars → 2 bytes + 6 padding
1 double → 8 bytes
( ! )
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
Even more interestingly …
struct S1 {
char c1;
double d;
char c2;
};
alignof(S1):8
sizeof(S1) :24
Based on the structure:
1 char → 1 byte + 7 padding
1 double → 8 bytes
1 char → 1 byte + 7 padding
struct S2 {
char c1;
char c2;
double d;
};
alignof(S2):8
sizeof(S2) :16
Based on the structure:
2 chars → 2 bytes + 6 padding
1 double → 8 bytes
struct S3 {
char c1;
float f;
char c2;
};
alignof(S3):4
sizeof(S3) :12
Based on the structure:
1 char → 1 byte + 3 padding
1 float → 4 bytes
1 char → 1 byte + 3 padding
struct S4 {
char c1;
char c2;
float f;
};
alignof(S4):4
sizeof(S4) :8
Based on the structure:
2 chars → 2 bytes + 2 padding
1 float → 4 bytes
( ! )
( ! )
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
Even more interestingly …
struct S1 {
char c1;
double d;
char c2;
};
alignof(S1):8
sizeof(S1) :24
Based on the structure:
1 char → 1 byte + 7 padding
1 double → 8 bytes
1 char → 1 byte + 7 padding
struct S2 {
char c1;
char c2;
double d;
};
alignof(S2):8
sizeof(S2) :16
Based on the structure:
2 chars → 2 bytes + 6 padding
1 double → 8 bytes
struct S3 {
char c1;
float f;
char c2;
};
alignof(S3):4
sizeof(S3) :12
Based on the structure:
1 char → 1 byte + 3 padding
1 float → 4 bytes
1 char → 1 byte + 3 padding
struct S4 {
char c1;
char c2;
float f;
};
alignof(S4):4
sizeof(S4) :8
Based on the structure:
2 chars → 2 bytes + 2 padding
1 float → 4 bytes
struct alignas(8) S5 {
char c1;
float f;
char c2;
};
alignof(S5):8
sizeof(S5) :16
Based on the structure:
1 char → 1 byte + 3 padding
1 float → 4 bytes
1 char → 1 byte + 3 padding
+ Even more padding … (*)
alignas(X)
( ! )
( ! )
C++ allows us to “Over-Align” data !
( * ) Probably so, as the C++ standard doesn’t specify how padding should be performed…
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
Note:
In reality, useless
Note:
They move�the world !
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
Note: Stack-allocated objects however will be properly aligned !
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
� a) We could overload the Global Memory Allocation to perform native (or some other special) alignment� Then new double[100]; , new int[100]; , … would all use that desired alignment.� But, we probably don’t want to do so as as the side-effects would be too broad.�� b) But if a particular class can leverage some performance-critical optimizations,� or we can “wrap” our desired datatype (the one we want to specially align) into a class / struct, � we can then overload that class’ / struct’s own operator new ([]) to perform some specific� type of Memory-Aligned Allocation … �
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
Controling Alignment – By-Example:��new double[100];
alignof(double):8
sizeof(double) :8�Dynamically Allocated array:�size: 100 x 4, but the alignment�of each of its elements on the�Freestore not guaranteed�to be at 8-byte boundaries�(if the starting address of the�first element happens to be�8-byte aligned, then yes, but�it is not guaranteed)
struct alignas(16) double_sse128 {
double data;
//overload operator new ([]) to control memory allocation alignment
void * operator new(std::size_t size) {
cout<<"Allocating "<< alignof(double_sse128) <<"-aligned. Object of size"<<size<<endl;
void * p = aligned_alloc(alignof(double_sse128), size);
if (p == nullptr) { throw std::bad_alloc(); }
return p;
}
void * operator new [](std::size_t size) {
cout<<"Allocating "<< alignof(double_sse128) <<"-aligned. Object Array of size"<<size<<endl;
void * p = aligned_alloc(alignof(double_sse128), size);
if (p == nullptr) { throw std::bad_alloc(); }
return p;
}
};
�Therefore we have for our custom double-wrapper type:
alignof(double_sse128): 16 , sizeof(double_sse128): 16
And will be aligned as desired whenever Dynamically Allocated !
Dynamic Memory Allocation
CS-202 C. Papachristos
Overloading operator new ([]) / operator delete ([])
What is the major benefit of having such flexibility ?
It is often desired in classes to manage all Dynamic Memory-relevant functionality� at the Low Level, in order to optimize its efficiency:
� In such cases it is common to wish to control allocation through explicitly chosen C low-level functions.� An example would be a class that wraps a dynamic container:� class DynamicContainer {� private: double * m_data;� public: …
};�� For such a case, the C low-level function realloc() would offer huge benefits, but designing it� into our class also requires to intervene at various levels of Dynamic Memory Management� (i.e. a simple new double[size] is not the way to go)…
Used to manage data of dynamically-determined sizes,�which can grow or shrink during runtime.
Dynamic Memory Management
CS-202 C. Papachristos
The Placement new ([ ]) Expression
Uses a special overload of operator new ([ ]) to construct an Object in the Freestore, at a known and properly pre-Allocated memory location.
void * operator new [] (std::size_t count, void * place);
The pointer that�Placement new ([])�received, forwarded.
Dynamic Memory Management
CS-202 C. Papachristos
The Placement new ([ ]) Expression
Syntax:
<type_id> * new (place_ptr) <type_id_ctor> ([SIZE] : optional)
Example:
Single Object
void * mem_mC = ::operator new( sizeof(MyClass) );
MyClass * myClass_Pt = new (mem_mC) MyClass("mine",1);
Allocate storage using the Global Allocation function
Construct Object in-Place
Dynamic Memory Management
CS-202 C. Papachristos
The Placement new ([ ]) Expression
Syntax:
<type_id> * new (place_ptr) <type_id_ctor> ([SIZE] : optional)
Example:
Single Object
void * mem_mC = ::operator new( sizeof(MyClass) );
MyClass * myClass_Pt = new (mem_mC) MyClass("mine",1);
Object Array is NOT so simple …
void * mem_mCA = ::operator new[](100 * sizeof(MyClass));
MyClass * myClassArr_Pt = new (mem_mCA) MyClass [100];
Allocate storage using the Global Allocation function
Construct Object in-Place
Remember, how do we know it’s just a multiple of an Object?
How do we know there’s no initial padding?
Dynamic Memory Management
CS-202 C. Papachristos
The Placement new ([ ]) Expression
Syntax:
<type_id> * new (place_ptr) <type_id_ctor> ([SIZE] : optional)
Example:
Single Object
void * mem_mC = ::operator new( sizeof(MyClass) );
MyClass * myClass_Pt = new (mem_mC) MyClass("mine",1);
Simple Datatype Arrays are safer …
void * char_buf = ::operator new[](100 * sizeof(char));
char * myDynamicCstr_Pt =� new (char_buf) char [100]{'L','o','r','e','m',…,'r','u','m','\0'};
Allocate storage using the Global Allocation function
Construct Object in-Place
For simpler built-in types we can be safer allocating memory buffers.
Dynamic Memory Management
CS-202 C. Papachristos
The Placement delete ([ ]) Expression
It really doesn’t exist in the C++ standard.�What we have are special overloads of operator delete ([ ]) that are invoked whenever Placement new ([]) throws an Exception…
void operator delete [] (void * ptr, void * place);
Dynamic Memory Management
CS-202 C. Papachristos
The Placement new ([ ]) Expression
Example Usage (Single Object):��Version 1: General Memory Buffer ( void * )
�void * mem_mC = ::operator new( sizeof(MyClass) );
MyClass * myClass_Pt = new (mem_mC) MyClass("mine",1);
�myClass_Pt->~MyClass();�::operator delete( mem_mC );�
Version 2: Byte-sized Type Memory Buffer ( char * )�
char * mem_mC = ::new char[ sizeof(MyClass) ];
MyClass * myClass_Pt = new (mem_mC) MyClass("mine",1);
�myClass_Pt->~MyClass();�::delete[]( mem_mC );
Time for Questions !
CS-202
CS-202 C. Papachristos