#include <string>
#include <list>
#include <algorithm>
#include <memory>
#include <iostream>

struct A
{
    std::string id ;
};

bool operator == ( const A& a, const std::string& str ) { return a.id == str ; }
bool operator < ( const A& first, const A& second ) { return first.id < second.id ; }

int main()
{
    std::list<A> seq { {"one"}, {"two"}, {"three"}, {"four"}, {"five"} } ;

    auto iter= std::find( std::begin(seq), std::end(seq), "three" ) ;
    A& alias = *iter ;
    A* ptr = std::addressof(alias) ;

    const auto dump = [&]
    {
        for( const auto& s : seq ) std::cout << s.id << ' ' ;
        std::cout << '\n' ;
        std::cout << iter->id << '/' << alias.id << '/' << ptr->id
                   << " at address " << ptr << "\n\n" ;
    };

    dump() ;

    seq.sort() ;
    dump() ;

    seq.insert( iter, { {"six"}, {"seven"}, {"eight"} } ) ;
    dump() ;

    seq.erase( std::find( std::begin(seq), std::end(seq), "four" ),
               std::find( std::begin(seq), std::end(seq), "seven" ) ) ;
    dump() ;

    seq.reverse() ;
    dump() ;

    // iterator/reference/pointer to A{"three"} have remained vaild till now
    // everything we have done upto here is a list operation
    // a list does not move its elements around in memory

    std::cout << "--------------------------\n" ;

    std::reverse(  std::begin(seq), std::end(seq) ) ;
    // iterator/reference/pointer to A{"three"} are now invalidated
    // iter no longer 'points' to A{"three"} etc.
    // the algorithm does move things around in memory
    dump() ;
}
