The University of Iowa
The College of Liberal Arts and Sciences
Department of Computer Science

Programming Languages and Tools:

CS:3210:0001

Lecture/Lab #21

Programming with C++

shared_ptr, pointers and run-time polymorphism

Warm up

  • What will be the output of the following program?

struct car
{
    car( std::string const& make_and_model )
        : make_and_model( make_and_model ) {}
    ~car() {
        std::cout << "Destroying " << make_and_model << std::endl; 
    }

    std::string const make_and_model;
};

int main() {
    std::vector<std::unique_ptr<car>> cars;
    cars.push_back( std::make_unique<car>( "Tesla Model X" ) );
    cars.push_back( std::make_unique<car>( "Honda Accord" ) );

    for ( auto const& c : cars )
        std::cout << c->make_and_model << std::endl;

    cars[0] = std::make_unique<car>( "Hyundai Sonata" );
    for ( auto const& c : cars )
        std::cout << c->make_and_model << std::endl;
}

shared_ptr

Shared object ownership

auto w = std::make_shared<widget>();
std::cout << "use_count: " << w.use_count() << std::endl;

if ( true ) {
    auto w2 = w;
    std::cout << "use_count: " << w.use_count() << std::endl;
    std::cout << "use_count: " << w2.use_count() << std::endl;
}

std::cout << "use_count: " << w.use_count() << std::endl;

shared_ptr (cont.)

T* ptr

[control block]*

T object

reference count

weak count

other data (custom deleter, etc.)

Control block

  • Twice the size of a raw pointer
  • Reference counter is dynamically allocated

 Primary characteristics: 

  • Reference counter increments/decrements are atomic
  • Supports custom deleters

shared_ptr<T>

Heap

Exercise 1

Use smart pointers to simplify memory management in the following program

  • Open the exercise template

  • Write your code, press Run to test

  • When you're done, grab your Repl's link and send it as a direct message to me (agurtovoy)

  • Click on the corresponding option in the "Lab21 exercises" poll in #general

Pointers and run-time polymorphism

struct car
{
    virtual void print( std::ostream& out ) const 
    { out << make_and_model; }
    
    std::string const make_and_model;
};

struct truck : car { // truck is-a car
    void print( std::ostream& out ) const override { 
        car::print( out );
        out << ", capacity: " << capacity; 
    }

    double capacity;
};

Containers of polymorphic objects

std::vector<car> cars;
cars.push_back( car( "Tesla Model X" ) );
cars.push_back( car( "Honda Accord" ) );
cars.push_back( truck( "Toyota Tacoma", 1620 ) );

for ( auto const& c : cars ) {
    c.print( std::cout );
    std::cout << std::endl;
}

Will this work?

Made with Slides.com