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

Programming Languages and Tools:

CS:3210:0001

Lecture/Lab #19

Programming with C++

std::optional, containers of polymorphic objects, std::unique_ptr

Course project

std::optional

std::optional<int> read_int(std::istream& in) {
    int n;
    if ( in >> n ) // check for errors
        return n;

    return {};
}

int main() {
    std::cout << "Enter an integer: ";
    if ( auto n = read_int( std::cin ) )
        std::cout << "You entered: " << *n << "\n";
    else
        std::cout << "Unexpected input\n";
}
  • Represents a value that may or may not be present
  • A common use case is the return value of a function that may fail

std::optional (cont.)

if ( x )

*x

Returns true if x contains a value

If x contains a value, returns a reference to the contained value, otherwise throws a std::bad_optional_access exception

if ( x.has_value() )

x.value()

If x contains a value, returns a reference to the contained value, otherwise the behavior is undefined.

Given std::optional<T> x ...

x.reset()

Destroys the contained value, if any

x = y;

Assigns x a new value; if x contains a value before the assignment, the contained value is destroyed by calling its destructor

x = obj;

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();

Will this work?

car

make_and_model

truck

make_and_model

capacity

car

vector<car>

v[0]

v[1]

v.size()

car

car

car

v[2]

Containers of polymorphic objects

How to make it work

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" ) );
cars.push_back( std::make_unique<truck>( "Toyota Tacoma", 1620 ) );

for ( auto const& c : cars )
    c->print();

car

"Tesla Model X"

vector<unique_ptr<car>>

v[0]

v[1]

v[2]

car

"Honda Accord"

truck

"Toyota Tacoma"

1620

Python vs C++

cars = []
cars.append( Car( "Tesla Model X" ) )
cars.append( Car( "Honda Accord" ) )
cars.append( Truck( "Toyota Tacoma", 1620 ) )

for c in cars:
    c.print()

Python

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" ) );
cars.push_back( std::make_unique<truck>( "Toyota Tacoma", 1620 ) );

for ( auto const& c : cars )
    c->print();

C++

std::unique_ptr

A "smart" pointer with exclusive ownership

  • Represents a pointer to a dynamically allocated object
  • Automatically manages the object's life time
  • Enables run-time polymorphism for collections of objects and factory functions
  • Is non-copyable, but moveable
  • Pointers to derived classes are implicitly convertible to pointers to the corresponding base class

std::unique_ptr (cont.)

std::unique_ptr<T> p;

Creates a unique_ptr instance that doesn't point to/manage any object.

auto p = std::make_unique<T>( ... )

Dynamically allocates a new object of type T by calling a corresponding constructor, takes ownership of the newly created object.

if ( p )

Returns true if p owns an object

*p

If p manages an object, returns a reference to the managed object, otherwise the behavior is undefined.

p->method( ... );

If p manages an object, calls the specified method of the managed object, otherwise the behavior is undefined.

q = std::move( p );

Moves the object ownership from p to q

Programming with C++, Spring 2020, Lecture #19

By Aleksey Gurtovoy

Programming with C++, Spring 2020, Lecture #19

std::optional, containers of polymorphic objects, std::unique_ptr

  • 625