C++ Classes & Dynamic Memory
C. Papachristos
Robotic Workers Lab
University of Nevada, Reno
CS-202
Course , Projects , Labs:
Your Next Project is going to be for X-tra grade (& optional) !
7th Project Deadline was this Wednesday 4/1.
Course Week
CS-202 C. Papachristos
Monday | Tuesday | Wednesday | Thursday | Friday | | Sunday |
|
|
| Lab (8 Sections) |
| | |
| CLASS | PASS Session | CLASS |
| | |
PASS Session | | Project DEADLINE | NEW Project | PASS Session | | PASS Session |
Today’s Topics
CS-202 C. Papachristos
Classes & Dynamic Memory
Dynamically Allocated Class Members
Dynamically Allocated Class Instances (Objects)
Class Memory Management
C++ Standard Library classes wrapping Dynamic Memory Management
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int & myClassFunc(){
MyClass mC;
mC.setIntVar(1);
cout << mC.getIntVar() << endl;
return mC.getIntVar();
}
int main(){
const int & p = myClassFunc();
…
cout << p ;
}
class MyClass {
public:
const int & getIntVar() const;
void setIntVar(int);
private:
int m_intVar;
};
Class Member Variable, bound to (an) Object.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int & myClassFunc(){
MyClass mC;
mC.setIntVar(1);
cout << mC.getIntVar() << endl;
return mC.getIntVar();
}
int main(){
const int & p = myClassFunc();
…
cout << p ;
}
class MyClass {
public:
const int & getIntVar() const;
void setIntVar(int);
private:
int m_intVar;
};
Class Member Variable, bound to (an) Object.
Class Constructor called as Block-Scope
local variable is defined.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int & myClassFunc(){
MyClass mC;
mC.setIntVar(1);
cout << mC.getIntVar() << endl;
return mC.getIntVar();
}
int main(){
const int & p = myClassFunc();
…
cout << p ;
}
class MyClass {
public:
const int & getIntVar() const;
void setIntVar(int);
private:
int m_intVar;
};
Class Member Variable, bound to (an) Object.
Class Constructor called as Block-Scope
local variable is defined.
Object Lifetime ended when it went Out-of-Scope, member is guaranteed to be Deallocated.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int m_intArr[ARRAY_MAX];
};
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int m_intArr[ARRAY_MAX];
};
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
Class Constructor called as Block-Scope, Array member�is guaranteed to be Allocated.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int m_intArr[ARRAY_MAX];
};
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
Class Constructor called as Block-Scope, Array member�is guaranteed to be Allocated.
Object Lifetime ended when it went Out-of-Scope, Array member is guaranteed to be Deallocated.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int * m_intArr;
};
A Pointer can be used to point to Dynamically Allocated�memory.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int * m_intArr;
};
Class Constructor called as Block-Scope,
local Pointer Variable guaranteed to be Defined.
A Pointer can be used to point to Dynamically Allocated�memory.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int * m_intArr;
};
A Pointer can be used to point to Dynamically Allocated�memory.
Class Constructor called as Block-Scope,
local Pointer Variable guaranteed to be Defined.
Class Destructor called as Object goes Out-of-Scope, local�Variable is destroyed, but not necessarily the Dyn. Memory.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory Management
Member Variables are wrapped by the Class.
const int DFLT_ARR[ARRAY_MAX] = {1,2,3};
const int * myClassFunc(){
MyClass mC;
mC.setIntArr(DFLT_ARR);
cout << mC.getIntArr()[1];
return mC.getIntArr();
}
int main(){
const int * p = myClassFunc();
…
cout << p[1] ;
}
class MyClass {
public:
const int * getIntArr() const;
void setIntArr(const int *);
private:
int * m_intArr;
};
void MyClass::setIntArr(const int *){
m_intArr = new int[3];
}
Class Destructor called as Object goes Out-of-Scope, local�Variable is destroyed, but not necessarily the Dyn. Memory.
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes can wrap Dynamic Memory
Raw Pointers can have different utility:
Class contains Object of another Class type: Allocation / deallocation automatically handled.
Chassis m_chassis;
Class references external Object via Pointer of another Class type. Memory Management for Object (might be) externally handled.
Driver * m_driver;
double * m_engTiming;
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Necessary for Object to be complete
Not a prerequisite
Necessary and Managing Dynamic Memory.
auto Storage-Duration.
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor) – the case until now:
Class Destructor (dtor) – the case until now:
class Car {
public:
Car();
Car(const Chassis & chass,
const double engT[VLV]=DFT_TIM);
Car(const Car & car);
~Car();
void setEngT(const double * e);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double m_engTiming[VLV];
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor) – the case until now:
Class Destructor (dtor) – the case until now:
class Car {
public:
Car();
Car(const Chassis & chass,
const double engT[VLV]=DFT_TIM);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double m_engTiming[VLV];
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor) – with Dynamic Memory:
Class Destructor (dtor) – with Dynamic Memory:
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor) – with Dynamic Memory:
Class Destructor (dtor) – with Dynamic Memory:
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor)
Parametrized Constructor:
Car::Car(const Chassis & chass,
const double * engT, int numVlv) {
//dynamic memory allocation at instantiation
m_engTiming = new double[numVlv]; // allocates !
m_numValve = numVlv; // assigns size !
m_chassis = chass; //Chassis assignment op/tor
}
Default Constructor:
Car::Car() : m_engTiming(nullptr)
{
//Chassis object auto-created based on its default ctor
//initialization of dynamic array size, no allocation
}
Note: What will happen here in case an Exception is thrown?
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor)
Default Constructor (revisited):
Car::Car()
: m_engTiming(nullptr) // initializes pointer !
, m_numValve(0) // initializes size !
{ }
Default Constructor – Bad
Car::Car(){
m_numValve = 0;
m_engTiming = new double[m_numValve];
}
Note:
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
(E.g. similar if attempting to invoke
Parametrized ctor with 0-size)
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor)
Copy-Constructor:
Car::Car(const Car & car){
//dynamic memory allocation at instantiation
m_engTiming = new double[car.m_numValve];
m_numValve = car.m_numValve;
for (int i=0; i<m_numValve; ++i)
m_engTiming[i] = car.m_engTiming[i];
m_chassis = car.m_chassis; //Chassis assignment op/tor
}
Allocate &
Deep-Copy
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Constructor (ctor)
Copy-Constructor:
Car::Car(const Car & car){
//dynamic memory allocation at instantiation
m_engTiming = new double[car.m_numValve];
m_numValve = car.m_numValve;
for (int i=0; i<m_numValve; ++i)
m_engTiming[i] = car.m_engTiming[i];
m_chassis = car.m_chassis; //Chassis assignment op/tor
}
Remember: The compiler automatically-synthesized one behaves like:
Car::Car(const Car & car){
m_chassis = car.chass; //ok (?)
m_engTiming = car.m_engTiming; //same memory (!)
m_numValve = car.m_numVlv; //ok
}
Shallow-Copy
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Allocate &
Deep-Copy
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Destructor (dtor)
Syntax:
Car::~Car(){
//Chassis object auto-destroyed (its dtor called)
//dynamic memory deallocation
delete [] m_engTiming;
//further cleanup ? – NO(…)
m_engTiming = nullptr;
m_numValve = 0;
}
Necessary
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Destructor (dtor)
Syntax:
Car::~Car(){
//Chassis object auto-destroyed (its dtor called)
//dynamic memory deallocation
delete [] m_engTiming;
//further cleanup ? – NO(…)
m_engTiming = nullptr;
m_numValve = 0;
}
Remember: Destructor is last thing called before object lifetime ends:
Not always a good idea
Necessary
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Destructor (dtor)
Remember, Placement new ([]) :
Car * myCar_Pt = new (some_preallocated_mem) Car();
myCar_Pt->~Car();
�const double * deletedData_Pt = myCar_Pt->getEngT();
::operator delete some_preallocated_mem;
Note :
We are not calling delete on it whose side-effects we saw in previous Lectures, but invoking the class dtor !
a) Explicit Destructor Call deletes Class-�managed Dynamic Data (m_engTiming)
c) Release pre-allocated buffer too.
b) What is the result in this “intermediate” state?
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double* engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Dynamically Allocated Class Members
Class Destructor (dtor)
Remember, Placement new ([]) :
Car * myCar_Pt = new (some_preallocated_mem) Car();
myCar_Pt->~Car();
�const double * deletedData_Pt = myCar_Pt->getEngT();
::operator delete some_preallocated_mem;
a) Explicit Destructor Call deletes Class-�managed Dynamic Data (m_engTiming)
c) Release pre-allocated buffer too.
b) What is the result in this “intermediate” state?
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double* engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
Car & operator=(const Car & other);
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes Dynamic Memory Management
Class Object Assignment
Remember: Default Object Assignment is Shallow-Copy.
Car & Car::operator=(const Car & other){
if (other.m_engTiming && …){ // possible checks
double * engTim = new double[other.m_numValve];
for(…){ engTim[i]=other.m_engTiming[i]; }
delete [] m_engTiming;
m_engTiming = engTim;
}
if (other.m_driver != nullptr){
// how do we want to do this? depends!
m_driver = other.m_driver;
}
m_chassis = other.m_chassis;
return *this;
}
Order of operations follows�scope of side-effects
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes Dynamic Memory Management
Class Object Assignment
The special case of Self-Assignment (+some bad coding of operator= )
Car * car_Pt = new Car(simpleChassis, 16);
Car * anotherCar_Pt = car_Pt;
*anotherCar_Pt = *car_Pt;
Car & Car::operator=(const Car & other){
…
delete [] m_engTiming;
if (other.m_numValve>0 && other.m_engTiming){
m_numValve = other.m_numValve;
try{
m_engTiming = new double[other.m_numValve];
for(…){ m_engTiming[i] = other.m_engTiming[i]; }
} catch(...) { /* handle exception */ }
} else{ m_numValve = 0; m_engTiming = nullptr; }
…
return *this;
}
What if?
Self-Assignment
Deletes its own content, and then re-copies own newly allocated data.
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
Car & operator=(const Car & other);
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Classes Dynamic Memory Management
Class Object Assignment
The special case of Self-Assignment (+some bad coding of operator= )
Car * car_Pt = new Car(simpleChassis, 16);
Car * anotherCar_Pt = car_Pt;
*anotherCar_Pt = *car_Pt;
Car & Car::operator=(const Car & other){
if (this != &other){
delete [] m_engTiming;
if (other.m_numValve>0 && other.m_engTiming){
m_numValve = other.m_numValve;
try{
m_engTiming = new double[other.m_numValve];
for(…){ m_engTiming[i] = other.m_engTiming[i]; }
} catch(...) { /* handle exception */ }
} else{ m_numValve = 0; m_engTiming = nullptr; }
}
return *this;
}
Check if calling object is the same as the one passed as parameter !
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
Car & operator=(const Car & other);
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Remember !
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Destructor(s)
Destructor Automatic activation clauses:
namespace ns{
Car myGlobalCar;
…
}
{ …
static Car myStaticCar;
…
}
a)
b)
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Destructor(s)
Destructor Automatic activation clauses:
namespace ns{
Car myGlobalCar;
…
}
{
Car myLocalCar;
…
}
{ …
static Car myStaticCar;
…
}
a)
b)
c)
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Destructor(s)
Destructor Automatic activation clauses:
namespace ns{
Car myGlobalCar;
…
}
{
Car myLocalCar;
…
}
Car * myCar_Pt = new Car();
…
delete myCar_Pt;
{ …
static Car myStaticCar;
…
}
a)
b)
c)
d)
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Copy-Constructor(s)
Copy Constructor activation clauses:
Car simpleCar(simpleChassis, 16);
Car myCar_cpy( simpleCar );
Car myCar_cpyInit = simpleCar;
a)
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Copy-Constructor(s)
Copy Constructor activation clauses:
Car simpleCar(simpleChassis, 16);
Car myCar_cpy( simpleCar );
Car myCar_cpyInit = simpleCar;
Car makeCar(const Driver * driver){
Car tempCar;
tempCar->setDriver( driver );
return tempCar;
}
a)
Local Object created
Copy-ctor to return value
can be “Elided” but behavior is similar
c)
b)
class Car {
public:
Car();
Car(Chassis chass, int numVlv=16);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
void setDriver(const Driver * d);
protected:
Chassis m_chassis;
Driver * m_driver;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Activation Clauses
Class Object Copy-Constructor(s)
Copy Constructor activation clauses:
Car simpleCar(simpleChassis, 16);
Car myCar_cpy( simpleCar );
Car myCar_cpyInit = simpleCar;
Car makeCar(const Driver * driver){
Car tempCar;
tempCar->setDriver( driver );
return tempCar;
}
bool carInspector(Car car){
const double * engT = car.getEngT();
if ( … ){ return true; } else { return false; }
}
a)
d)
Local Object created
Copy-ctor to return value
can be “Elided” but behavior is similar
c)
Copy-ctor to pass value
=
b)
Classes & Dynamic Memory
CS-202 C. Papachristos
Class Objects in Dynamic Memory
Dynamically Allocated Class Object
Example:
Chassis superCarChassis( … );
Car * myCar_Pt = new Car(superCarChassis, dfltTims, 24);
double superCarTimings[24] = {…,…,…};
myCar_Pt->setEngT(superCarTimings);
myCar_Pt->getChassis().setColor(…);
delete myCar_Pt;
Expression new - Invocation of Constructor:
But is in itself entirely a Dynamically Allocated Variable:
Everything as per usual Pointer notation.
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Classes & Dynamic Memory
CS-202 C. Papachristos
Class Objects in Dynamic Memory
Class Object
Example:
Chassis superCarChassis( … );
Car * myCar_Pt = new Car(superCarChassis, dfltTims, 24);
double superCarTimings[24] = {…,…,…};
myCar_Pt->setEngT(superCarTimings);
myCar_Pt->getChassis().setColor(…);
delete myCar_Pt;
Expression delete - Invocation of Destructor:
Remember:
Everything as per usual Pointer notation.
class Car {
public:
Car();
Car(const Chassis & chass,
const double * engT, int numVlv);
Car(const Car & car);
~Car();
void setEngT(const double * engT);
const double * getEngT() const;
Chassis & getChassis();
protected:
Chassis m_chassis;
private:
double * m_engTiming;
int m_numValve;
};
Smart Pointers
CS-202 C. Papachristos
Case of an algorithmic Pipeline leveraging Dynamic Memory:
Object * create_object( … ) {
object * o = new (std::nothrow) Object( … );
return o;
}
Object * startup_worker(Object * o_in, Worker * & w_out){
Object * o_for_worker;
if ( !o_in->verify_something( … ) )
o_for_worker = create_object( … );
else
o_for_worker = o_in;
o_for_worker->modify_something( … );
w_out = new (std::nothrow) Worker( …, o_for_worker, … );
return o_for_worker;
}
a)
a) So if the o_in we received is not verified, then we invoke a different create_object. But does this mean we are done with the Dynamic Data managed by o_in? Or are they used anywhere else in the pipeline?�b) So the o_for_worker is also modified. This means the Dynamic Data managed by o_in might. Also, we return the o_for_worker which means we will probablt have some use for it outside the function.�c) So o_for_worker is also passed to the constructor of another Dynamically created Worker object… So who manages the lifetime of the o_for_worker dynamic Data? How can we keep track and coordinate it all?
b)
b)
c)
Smart Pointers
CS-202 C. Papachristos
If only Pointers were “Smart” enough to know when the Dynamic Data they manage are no longer of any use…
a) When they come into existence, they start managing some Dynamic Memory:� Possibly dynamically creating new objects (through new ([])), or� Possibly binding themselves to some already allocated Dynamic Memory, and even� sharing it together with other “Smart Pointer” objects.
� b) At the end of their lifetime, they can tally up whether there exist other “Smart Pointer” objects still alive that are still managing the same memory.
If there aren’t, this signifies that the Dynamic Memory resource is no longer used by� the program, so they Deallocate it (through delete ([])) to avoid Leaking Memory.
Smart Pointers
CS-202 C. Papachristos
If only Pointers were “Smart” enough to know when the Dynamic Data they manage are no longer of any use…
In C++ this is an Idiom called Resource Acquisition Is Initialization (RAII).�
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Note:
make_shared<T> is a special function that Dynamically Allocates and Constructs a T object, and then creates and returns a shared_ptr<T> that wraps its Dynamic Memory management.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{
std::shared_ptr<Car> sp_c_loc = std::make_shared<Car>(1500.0, "ABCDEF");
}
Invokes Dynamic Memory construction, i.e.�new Car(1500.0, "ABCDEF");
Shared Pointer Object of type�std::shared_ptr<Car>
is constructed inside the local scope here
Shared Pointer Object of type std::shared_ptr<Car> is destroyed with the end of the scope.� At this point, the Shared Pointer class Destructor also takes care of the Dynamic Memory
Destruction & Deallocation, i.e. invokes delete on the internally managed memory it newed before.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{ //Scope A
std::shared_ptr<Car> sp_A;
{ //Scope B
std::shared_ptr<Car> sp_B = std::make_shared<Car>(1500.0, "ABCDEF");
sp_A = sp_B;
}
}
A) Shared Pointer Object sp_A has a Lifetime limited by Scope A.
Its constructor is invoked when Scope A begins, and its destructor when Scope A ends.
sp_A initially manages no Dynamic Memory object.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{ //Scope A
std::shared_ptr<Car> sp_A;
{ //Scope B
std::shared_ptr<Car> sp_B = std::make_shared<Car>(1500.0, "ABCDEF");
sp_A = sp_B;
}
}
B) Shared Pointer Object sp_B has a Lifetime limited by Scope B.
Once created, sp_B starts managing a Dyn. Memory object of type Car, constructed with make_shared.
The Lifetime of the Car Dyn. Memory is limited by the Lifetime of its managing Shared Pointer sp_B.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{ //Scope A
std::shared_ptr<Car> sp_A;
{ //Scope B
std::shared_ptr<Car> sp_B = std::make_shared<Car>(1500.0, "ABCDEF");
sp_A = sp_B;
}
}
C) The Shared Pointer Assignment sp_A = sp_B means they now share ownership of the same Dyn. Memory.
Now both of them manage the Lifetime of the Dyn. Memory object of type Car.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{ //Scope A
std::shared_ptr<Car> sp_A;
{ //Scope B
std::shared_ptr<Car> sp_B = std::make_shared<Car>(1500.0, "ABCDEF");
sp_A = sp_B;
}
}
D) Ending Scope B means the sp_B will get Destroyed. But there is still a “reference” to the Dyn. Memory it manages, through sp_A. So this is not yet the end of the Lifetime of the Dyn. Memory Car.
Smart Pointers
CS-202 C. Papachristos
The std::shared_ptr<T> class
{ //Scope A
std::shared_ptr<Car> sp_A;
{ //Scope B
std::shared_ptr<Car> sp_B = std::make_shared<Car>(1500.0, "ABCDEF");
sp_A = sp_B;
}
}
E) Ending Scope A means the sp_A will get Destroyed.
This is the last Shared Pointer holding a “reference” to the Dyn. Memory Car.
So with the end of its Lifetime, sp_A also Destroys & Deallocates the Dyn. Memory Car.
Smart Pointers
CS-202 C. Papachristos
The std::unique_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::unique_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Note:
make_unique<T> acts in a similar convenience-fashion to make_shared<T> it was however only introduced in the C++14 Standard…
Smart Pointers
CS-202 C. Papachristos
The std::unique_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Smart Pointers
CS-202 C. Papachristos
The std::unique_ptr<T> class
Note: The T in the syntax above can be substituted by any type we wish to manage (more on that later…)� So shared_ptr<int> is a “Smart Pointer” that manages Dynamically Allocated integers,� shared_ptr<Car> is a “Smart Pointer” that manages Dynamically Allocated class Car objects, etc.� Think of it for now in relevant terms to int *, Car *. �
Will not even compile !
Class unique_ptr<T> has its Copy Constructor and Assignment Operator completely disabled!
String
CS-202 C. Papachristos
std::string
The Standard String Class – (actually std::basic_string<char> , more on that later)
Necessary Header to include (implementation comes with the C++ Standard Library):�#include <string>�/* using namespace std; */
Standard String variables and expressions are treated much like simple types.
String
CS-202 C. Papachristos
std::string
Standard String, by-Example:
String
CS-202 C. Papachristos
std::string
Input / Output with Standard String(s)
Treated like other types:
std::string s1, s2;� std::cin >> s1;� std::cin >> s2;
User input:� Today is a beautiful day!
Output:
std::cout << s1 << " " << s2 ;
s1 has received the value "Today"�s2 has received the value "is"
Note:
Extraction still ignores whitespace.
String
CS-202 C. Papachristos
std::string
Input / Output with Standard String(s)
Usage with getline() for complete lines :
std::string line;� std::getline(std::cin, line);� std::cout << line << "END";
Can specify Delimiter character :
� std::string line;� std::getline(std::cin, line, '?');
Input:
How are you? Fine I hope!
Output:�How are you? Fine I hope!END
Similar to a c-string’s usage of getline().
Receives input until char '?' encountered.
Input:
How are you? Fine I hope!
Output:�How are youEND
String
CS-202 C. Papachristos
std::string
Conversion between C-string(s) & Standard String(s)
char cString[] = "My C-string";� std::string stringObj;
Must use appropriate c-String method:� strcpy( cString, stringObj.c_str() );
Illegal
Legal, uses String’s appropriate�Assignment Operator ( = ) overload.
String
CS-202 C. Papachristos
std::string
Time for Questions !
CS-202
CS-202 C. Papachristos