1 of 64

C++ Classes & Dynamic Memory

C. Papachristos

Robotic Workers Lab

University of Nevada, Reno

CS-202

2 of 64

Course , Projects , Labs:

Your Next Project is going to be for X-tra grade (& optional) !

7th Project Deadline was this Wednesday 4/1.

  • NO Project accepted past the 24-hrs delayed extension (@ 20% grade penalty).
  • Send what you have in time!

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

3 of 64

Today’s Topics

CS-202 C. Papachristos

Classes & Dynamic Memory

Dynamically Allocated Class Members

Dynamically Allocated Class Instances (Objects)

Class Memory Management

  • Constructor(s)
  • Destructor(s)
  • Assignment

C++ Standard Library classes wrapping Dynamic Memory Management

  • std::shared_ptr
  • std::unique_ptr
  • std::string

4 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • auto Storage-Duration.
  • Goes away with Stack Frame that created it, Stack Frame that created the Class Object.

5 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • auto Storage-Duration.
  • Goes away with Stack Frame that created it, Stack Frame that created the Class Object.

Class Constructor called as Block-Scope

local variable is defined.

6 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • auto Storage-Duration.
  • Goes away with Stack Frame that created it, Stack Frame that created the Class 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.

7 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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];

};

  • auto Storage-Duration Array.
  • Created-allocated with the Class Object.
  • Goes away-deallocated with the Class Object.
  • No need to handle Memory Management.

const int DFLT_ARR[ARRAY_MAX] = {1,2,3};

8 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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];

};

  • auto Storage-Duration Array.
  • Created-allocated with the Class Object.
  • Goes away-deallocated with the Class Object.
  • No need to handle Memory Management.

const int DFLT_ARR[ARRAY_MAX] = {1,2,3};

Class Constructor called as Block-Scope, Array member�is guaranteed to be Allocated.

9 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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];

};

  • auto Storage-Duration Array.
  • Created-allocated with the Class Object.
  • Goes away-deallocated with the Class Object.
  • No need to handle Memory Management.

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.

10 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • Pointer Variable created with the Class Object.
  • Pointer Variable goes away with the Class Object.
  • Need to handle Dynamic Memory it points to.

11 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • Pointer Variable created with the Class Object.
  • Pointer Variable goes away with the Class Object.
  • Need to handle Dynamic Memory it points to.

12 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

  • Pointer Variable created with the Class Object.
  • Pointer Variable goes away with the Class Object.
  • Need to handle Dynamic Memory it points to.

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.

13 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory Management

Member Variables are wrapped by the Class.

  • As within a block scope, much of memory management is auto-handled.

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.

14 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Classes can wrap Dynamic Memory

Raw Pointers can have different utility:

  • Remember: Composition

Class contains Object of another Class type: Allocation / deallocation automatically handled.

Chassis m_chassis;

  • Remember: Aggregation

Class references external Object via Pointer of another Class type. Memory Management for Object (might be) externally handled.

Driver * m_driver;

  • Class employs Dynamic Data. Memory Management handled in Class Methods.

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.

15 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Dynamically Allocated Class Members

Class Constructor (ctor) – the case until now:

  • No Dynamic Storage-Duration members.
  • Constructor mainly for controlled Member initialization.
  • Its presence is tentative, Class can be initialized via a combination of setEngTiming, getChassis.

Class Destructor (dtor) – the case until now:

  • Nothing to do, auto Storage-Duration Members get deallocated when the Class Object is destroyed.
  • An Object’s Destructor when called, invokes the Destructor of all its Member Objects.

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];

};

16 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Dynamically Allocated Class Members

Class Constructor (ctor) – the case until now:

  • No Dynamic Storage-Duration members.
  • Constructor mainly for controlled Member initialization.
  • Its presence is tentative, Class can be initialized via a combination of setEngTiming, getChassis.

Class Destructor (dtor) – the case until now:

  • Nothing to do, auto Storage-Duration Members get deallocated when the Class Object is destroyed.
  • An Object’s Destructor when called, invokes the Destructor of all its Member Objects; In effect:
  • Frees memory of m_engineTiming known-size array.
  • Calls dtor of m_chassis.

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];

};

17 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Dynamically Allocated Class Members

Class Constructor (ctor) – with Dynamic Memory:

  • A Raw Pointer member can be used to point to a memory location with data, but this has to be allocated.
  • Otherwise: Undefined Behavior�(best case scenario is a clear Segmentation Fault !)
  • Typically, ctor might perform initial allocation.

Class Destructor (dtor) – with Dynamic Memory:

  • An Object’s dtor when called, invokes the dtor of all its Member Objects.
  • But a Raw Pointer member is just a variable, if it points to Dynamic Memory it has to be explicitly Deallocated.
  • Otherwise: Memory Leak !

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;

};

18 of 64

Classes & Dynamic Memory

CS-202 C. Papachristos

Dynamically Allocated Class Members

Class Constructor (ctor) – with Dynamic Memory:

  • A Raw Pointer member can be used to point to a memory location with data, but this has to be allocated.
  • Otherwise: Undefined Behavior�(best case scenario is a clear Segmentation Fault !)
  • Typically, ctor might perform initial allocation.

Class Destructor (dtor) – with Dynamic Memory:

  • An Object’s dtor when called, invokes the dtor of all its Member Objects.
  • But a Raw Pointer member is just a variable, if it points to Dynamic Memory it has to be explicitly Deallocated.
  • Otherwise: Memory Leak !

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;

};

19 of 64

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;

};

20 of 64

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:

  • “When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.”
  • “The effect of dereferencing a pointer returned as a request for zero size�is Undefined.”
  • “Even if the size of the space requested by new is 0, the request can fail.”

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)

21 of 64

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;

};

22 of 64

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

23 of 64

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;

};

24 of 64

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:

  • No sense incurring set overhead (think cases where 1000’s of Objects are allocated/deallocated).
  • Usually mentioned rationale of setting Pointers back to nullptr suggests they will be reused (e.g. act as a safeguard mechanism, “what if my code tries to access memory after it’s been deleted?”)

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;

};

25 of 64

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;

};

26 of 64

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;

  • After non-trivial Destructor called, Object “… no longer exists”.
  • “... after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways... The program has undefined behavior if ... the pointer is used to access a non-static data member or call a non-static member function of the object.

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;

};

27 of 64

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.

  • Dynamic Memory allocation/deallocation requires overloading of the assignment operator ( = ):

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

28 of 64

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;

};

29 of 64

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 !

30 of 64

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:

  • Global Object or Object with static Storage-Duration (Namespace-Scope), when program terminates:

namespace ns{

Car myGlobalCar;

}

{ …

static Car myStaticCar;

}

a)

b)

31 of 64

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:

  • Global Object or Object with static Storage-Duration (Namespace-Scope), when program terminates:

namespace ns{

Car myGlobalCar;

}

  • Local Object (Block-Scope), when it goes Out-of-Scope:

{

Car myLocalCar;

}

{ …

static Car myStaticCar;

}

a)

b)

c)

32 of 64

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:

  • Global Object or Object with static Storage-Duration (Namespace-Scope), when program terminates:

namespace ns{

Car myGlobalCar;

}

  • Local Object (Block-Scope), when it goes Out-of-Scope:

{

Car myLocalCar;

}

  • Pointer to Object of Dynamic Storage-Duration gets delete’d:

Car * myCar_Pt = new Car();

delete myCar_Pt;

{ …

static Car myStaticCar;

}

a)

b)

c)

d)

33 of 64

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:

  • Explicit activation – instantiate an Object by making use of another Object – Reminder: (b) is Copy-Initialization :

Car simpleCar(simpleChassis, 16);

Car myCar_cpy( simpleCar );

Car myCar_cpyInit = simpleCar;

a)

34 of 64

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:

  • Explicit activation – instantiate an Object by making use of another Object – Reminder: (b) is Copy-Initialization :

Car simpleCar(simpleChassis, 16);

Car myCar_cpy( simpleCar );

Car myCar_cpyInit = simpleCar;

  • Function returns Object By-Value:

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)

35 of 64

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:

  • Explicit activation – instantiate an Object by making use of another Object – Reminder: (b) is Copy-Initialization :

Car simpleCar(simpleChassis, 16);

Car myCar_cpy( simpleCar );

Car myCar_cpyInit = simpleCar;

  • Function returns Object By-Value:

Car makeCar(const Driver * driver){

Car tempCar;

tempCar->setDriver( driver );

return tempCar;

}

  • Function parameter is an Object passed By-Value:

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)

36 of 64

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:

  • Functionally behaves as per the usual, allocating auto Storage-Duration members automatically and Dynamic Memory Members as instructed.

But is in itself entirely a Dynamically Allocated Variable:

  • All its Members will be allocated on the Freestore, regardless if they are “regular” objects or dynamically allocated variables.

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;

};

37 of 64

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:

  • Functionally behaves the same, deallocating auto Storage-Duration members automatically and Dynamic Memory Members as instructed.

Remember:

  • Calls Destructors of all Member Variables.
  • Has to be explicitly instructed to delete any Dynamically Allocated space, will not work “magically” - recursively.

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;

};

38 of 64

Smart Pointers

CS-202 C. Papachristos

Case of an algorithmic Pipeline leveraging Dynamic Memory:

  • Dynamic Memory is created.
    • Using a Pointer !

  • Data are passed around from function to function.
    • Using Pointers !

  • Dyn. Memory has to be eventually deallocated.
    • Using a Pointer !

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)

39 of 64

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…

  • We could design special “Smart Pointer” wrapper classes like that, which:

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.

40 of 64

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).�

  • C++11 introduced wrapper classes for Dynamic Memory management:
    • std::shared_ptr� The Reference-counted smart pointer.
    • std::weak_ptr� The State-observer (of another shared_ptr) smart pointer.
    • std::unique_ptr� The Single-ownership smart pointer.

41 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can create a Shared Pointer that�a) Manages no Dynamic Memory:� std::shared_ptr<int> sp_i; � “Like” saying: int * p_i = nullptr;

42 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can create a Shared Pointer that�a) Manages no Dynamic Memory:� std::shared_ptr<int> sp_i; � “Like” saying: int * p_i = nullptr;b) Manages some Dynamic Memory that is just instantiated:� std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");� “Like” saying: int * p_c = new Car(1500.0, "ABCDEF");

43 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can create a Shared Pointer that�a) Manages no Dynamic Memory:� std::shared_ptr<int> sp_i; � “Like” saying: int * p_i = nullptr;b) Manages some Dynamic Memory that is just instantiated:� std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");� “Like” saying: int * p_c = new Car(1500.0, "ABCDEF");

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.

44 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can create a Shared Pointer that�a) Manages no Dynamic Memory:� std::shared_ptr<int> sp_i; � “Like” saying: int * p_i = nullptr;b) Manages some Dynamic Memory that is just instantiated:� std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");� “Like” saying: int * p_c = new Car(1500.0, "ABCDEF");c) Starts Co-Managing the same Dynamic Memory as another Shared Pointer object:� std::shared_ptr<Car> sp_c_2 = sp_c; “Like” saying: int * p_c_2 = p_c;

45 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can access a Shared Pointer:�std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");d) To check whether the underlying managed pointer is a “Null Pointer(relies on an operator bool() method):� if ( sp_c ) { … } or if ( !sp_c ) { … } � “Like” saying: Car * p_c; … if (p_c == nullptr) { … } or if (p_c != nullptr) { … }

46 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can access a Shared Pointer:�std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");d) To check whether the underlying managed pointer is a “Null Pointer(relies on an operator bool() method):� if ( sp_c ) { … } or if ( !sp_c ) { … } � “Like” saying: Car * p_c; … if (p_c == nullptr) { … } or if (p_c != nullptr) { … } e) To Dereference the underlying managed Dynamic Memory object:� cout << *sp_c ; The operator *() method returns a Reference to the managed Car (generally T) object � sp_c->drive(); The operator ->() method returns a Pointer to the managed Car (generally T) object

47 of 64

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 *.

  • A Shared Pointer allows managing Dynamic Memory with shared ownership.
  • We can access a Shared Pointer:�std::shared_ptr<Car> sp_c = std::make_shared<Car>(1500.0, "ABCDEF");d) To check whether the underlying managed pointer is a “Null Pointer(relies on an operator bool() method):� if ( sp_c ) { … } or if ( !sp_c ) { … } � “Like” saying: Car * p_c; … if (p_c == nullptr) { … } or if (p_c != nullptr) { … } e) To Dereference the underlying managed Dynamic Memory object:� cout << *sp_c ; The operator *() method returns a Reference to the managed Car (generally T) object � sp_c->drive(); The operator ->() method returns a Pointer to the managed Car (generally T) objectf) To even get the Value of the underlying memory pointer:� Car * car_pt = sp_c.get(); We get the Address of the internally managed Dyn. Memory object.

48 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Dynamic Memory & Lifetime Management, by-Example:

{

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.

49 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Shared Ownership & Lifetime Management, by-Example:

{ //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.

50 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Shared Ownership & Lifetime Management, by-Example:

{ //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.

51 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Shared Ownership & Lifetime Management, by-Example:

{ //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.

52 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Shared Ownership & Lifetime Management, by-Example:

{ //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.

53 of 64

Smart Pointers

CS-202 C. Papachristos

The std::shared_ptr<T> class

  • Shared Ownership & Lifetime Management, by-Example:

{ //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.

54 of 64

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 *.

  • A Unique Pointer allows managing Dynamic Memory with single ownership.
  • We can create a Unique Pointer that�a) Manages no Dynamic Memory:� std::unique_ptr<int> up_i;

55 of 64

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 *.

  • A Unique Pointer allows managing Dynamic Memory with single ownership.
  • We can create a Unique Pointer that�a) Manages no Dynamic Memory:� std::unique_ptr<int> up_i; b) Manages some Dynamic Memory that is just instantiated:� std::unique_ptr<Car> up_c = std::make_unique<Car>(1500.0, "ABCDEF");

Note:

make_unique<T> acts in a similar convenience-fashion to make_shared<T> it was however only introduced in the C++14 Standard…

56 of 64

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 *.

  • A Unique Pointer allows managing Dynamic Memory with single ownership.
  • We can create a Unique Pointer that�a) Manages no Dynamic Memory:� std::unique_ptr<int> up_i; b) Manages some Dynamic Memory that is just instantiated:� std::shared_ptr<Car> up_c = std::make_unique<Car>(1500.0, "ABCDEF");c) We CANNOT Co-Manage the same Dynamic Memory as another Unique Pointer :� std::unique_ptr<Car> up_c_cpy = up_c;� std::unique_ptr<Car> up_c_assign;� up_c_assign = up_c;

57 of 64

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 *.

  • A Unique Pointer allows managing Dynamic Memory with single ownership.
  • We can create a Unique Pointer that�a) Manages no Dynamic Memory:� std::unique_ptr<int> up_i; b) Manages some Dynamic Memory that is just instantiated:� std::shared_ptr<Car> up_c = std::make_unique<Car>(1500.0, "ABCDEF");c) We CANNOT Co-Manage the same Dynamic Memory as another Unique Pointer :� std::unique_ptr<Car> up_c_cpy = up_c;� std::unique_ptr<Car> up_c_assign;� up_c_assign = up_c;

Will not even compile !

Class unique_ptr<T> has its Copy Constructor and Assignment Operator completely disabled!

58 of 64

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.

  • Can assign, compare, add:�std::string s1("Hello "), s2("World!"); //c-string based String constructorstd::string s3 = s1 + s2; //String concatenation�s3 = "Hello Mom!" //String assignment

59 of 64

String

CS-202 C. Papachristos

std::string

Standard String, by-Example:

60 of 64

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.

61 of 64

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.

  • Does not append Delimiter to String.

Input:

How are you? Fine I hope!

Output:�How are youEND

62 of 64

String

CS-202 C. Papachristos

std::string

Conversion between C-string(s) & Standard String(s)

char cString[] = "My C-string";� std::string stringObj;

  • From c-String to Standard String object:stringObj = cString;

  • From a Standard String object to c-String:�cString = stringObj;

Must use appropriate c-String method:� strcpy( cString, stringObj.c_str() );

Illegal

Legal, uses String’s appropriate�Assignment Operator ( = ) overload.

63 of 64

String

CS-202 C. Papachristos

std::string

64 of 64

Time for Questions !

CS-202

CS-202 C. Papachristos