Advance Tools and Techniques
Overloading new and delete
Specialized operators can give more flexibility in how
and when memory allocation and de-allocation occur
Run-Time Type Identification
Can obtain type specific information from an object
Can allow access to derived class methods and
members through a pointer/reference to a base class
Pointer to Class Member
Can be used to identify a data member or a member
function or operator within an object
CSE 332: C++ Advanced Tools and Techniques
Operators new and delete are Inverses
string *sp = new string ("a value");
string *arr = new string[10];
Three steps occur when new is called
A library function named operator new (or operator new[]) is called,
which allocates raw, untyped memory from the heap
Placement version of new is passed pointer to existing memory, and skips this step
The appropriate constructor(s) is(are) called to construct the object(s) from
the initializers
A pointer to the newly allocated and constructed object is returned as the
expressions value
delete sp;
delete [] arr;
Three steps occur when delete is called (inverse of for new)
A pointer to the memory to be de-allocated is passed as a parameter
A destructor is run at the position (version without []) or destructors are run
at all positions (version with []) to the parameter points
Memory is returned to the heap by calling library function operator delete
or operator delete[]
CSE 332: C++ Advanced Tools and Techniques
Interfaces for Operators new and delete
// might throw
void *operator
void *operator
void *operator
void *operator
an exception
new(size_t);
new[](size_t);
delete(void*) noexcept;
delete[](void*) noexcept;
// promise not
void *operator
void *operator
void *operator
void *operator
to throw
new(size_t, nothrow_t&) noexcept;
new[](size_t, nothrow_t&) noexcept;
delete(void*, nothrow_t&) noexcept;
delete[](void*, nothrow_t&) noexcept;
// placement new operators dont allocate: just call
// constructor(s) starting at passed address, return it
void *operator new(size_t, void*); // cant redefine
void *operator new[](size_t, void*);
CSE 332: C++ Advanced Tools and Techniques
Implementations of Operators new and delete
// From LLM pp. 823
void *operator new(size_t size) {
if (void *meme = malloc(size))
return meme;
else
throw bad_alloc();
}
void operator delete (void *meme) noexcept {
free (meme);
}
CSE 332: C++ Advanced Tools and Techniques
Run-Time Type Identification
The dynamic_cast operator returns a pointer or reference to a more specific
(derived) type if it can
Only can be used with pointers to structs or classes with virtual methods
The dynamic_cast operator returns nullptr (or throws an exception) if it cannot downcast
to the specified type
dynamic_cast<type*> (base) // returns a pointer
dynamic_cast<type&> (base) // returns an l-value reference
dynamic_cast<type&&> (base) // returns an r-value reference
The typeid operator returns a type_info for a given expression
Works with built-in types as well as user-declared types
Cannot declare or construct type_info objects explicitly
Can only use implicitly via expressions involving the typeid operator and operators and
methods available for type_info objects, e.g.,
cout << "e is of type " << typeid(e).name() << endl;
cout << " f is of type " << typeid(f).name() << endl;
cout << " the types are " <<
(typeid(e) == typeid(f) ? " " : " not ") <<
"the same" << endl;
CSE 332: C++ Advanced Tools and Techniques
Run-Time Type Identification Example
bool same_cage (Animal * a, Animal * b) {
// only ok if both are Pandas
return dynamic_cast<Panda *>(a) &&
dynamic_cast<Panda *>(b);
}
Output:
We have a struct Grizzly
and a struct Panda
Dont put in same cage!
int main (int, char * []) {
Animal *a = new Grizzly ();
Animal *b = new Panda ();
cout << "we have a "
<< typeid(*a).name() << endl << "and a "
<< typeid(*b).name() << endl << endl;
if (!same_cage(a, b)) {
cout << "Dont put in same cage!" << endl;
}
delete a; delete b;
return 0;
}
CSE 332: C++ Advanced Tools and Techniques
Pointer to Data Member
struct Truck {
Truck (unsigned int w): weight_(w) {
cout << "weight: " << weight_ << endl;}
unsigned int weight_;
};
int main (int, char * []) {
Truck trucks [] = {902, 900};
auto weight_ptr = &Truck::weight_; // data
Output:
weight: 902
weight: 900
Truck weights are:
Truck 0 weight is 902
Truck 1 weight is 900
cout << "Truck weights are: " << endl;
for (Truck* truck_ptr = trucks;
truck_ptr - trucks <
sizeof(trucks)/sizeof(Truck);
++truck_ptr) {
cout << "Truck " << truck_ptr - trucks
<< " weight is "
<< truck_ptr->*weight_ptr
<< endl;
}
return 0;
}
CSE 332: C++ Advanced Tools and Techniques
Pointer to Member Function
class Truck {
public:
Output:
Truck (unsigned int w): weight_(w) {
cout << "weight: " << weight_ << endl;}
weight: 902
unsigned int weight() {return weight_;}
weight: 900
private:
Truck weights are:
unsigned int weight_;
Truck 0 weight is 902
};
Truck 1 weight is 900
int main (int, char * []) {
Truck trucks [] = {902, 900};
// declaration almost identical to previous
auto weight_ptr = &Truck::weight; // fxn
cout << "Truck weights are: " << endl;
for (Truck* truck_ptr = trucks;
truck_ptr - trucks <
sizeof(trucks)/sizeof(Truck);
++truck_ptr) {
cout << "Truck " << truck_ptr - trucks
<< " weight is "
<< (truck_ptr->*weight_ptr)() << endl; // note how parens are used
}
return 0;
}
CSE 332: C++ Advanced Tools and Techniques