123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- //
- // Boost.Pointer Container
- //
- // Copyright Thorsten Ottosen 2003-2005. Use, modification and
- // distribution is subject to the Boost Software License, Version
- // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // For more information, see http://www.boost.org/libs/ptr_container/
- //
- //
- // This example is intended to get you started.
- // Notice how the smart container
- //
- // 1. takes ownership of objects
- // 2. transfers ownership
- // 3. applies indirection to iterators
- // 4. clones objects from other smart containers
- //
- //
- // First we select which container to use.
- //
- #include <boost/ptr_container/ptr_deque.hpp>
- //
- // we need these later in the example
- //
- #include <boost/assert.hpp>
- #include <string>
- #include <exception>
- //
- // Then we define a small polymorphic class
- // hierarchy.
- //
- class animal : boost::noncopyable
- {
- virtual std::string do_speak() const = 0;
- std::string name_;
- protected:
- //
- // Animals cannot be copied...
- //
- animal( const animal& r ) : name_( r.name_ ) { }
- void operator=( const animal& );
- private:
- //
- // ...but due to advances in genetics, we can clone them!
- //
- virtual animal* do_clone() const = 0;
-
- public:
- animal( const std::string& name ) : name_(name) { }
- virtual ~animal() throw() { }
-
- std::string speak() const
- {
- return do_speak();
- }
- std::string name() const
- {
- return name_;
- }
- animal* clone() const
- {
- return do_clone();
- }
- };
- //
- // An animal is still not Clonable. We need this last hook.
- //
- // Notice that we pass the animal by const reference
- // and return by pointer.
- //
- animal* new_clone( const animal& a )
- {
- return a.clone();
- }
- //
- // We do not need to define 'delete_clone()' since
- // since the default is to call the default 'operator delete()'.
- //
- const std::string muuuh = "Muuuh!";
- const std::string oiink = "Oiiink";
- class cow : public animal
- {
- virtual std::string do_speak() const
- {
- return muuuh;
- }
- virtual animal* do_clone() const
- {
- return new cow( *this );
- }
- public:
- cow( const std::string& name ) : animal(name) { }
- };
- class pig : public animal
- {
- virtual std::string do_speak() const
- {
- return oiink;
- }
- virtual animal* do_clone() const
- {
- return new pig( *this );
- }
-
- public:
- pig( const std::string& name ) : animal(name) { }
- };
- //
- // Then we, of course, need a place to put all
- // those animals.
- //
- class farm
- {
- //
- // This is where the smart containers are handy
- //
- typedef boost::ptr_deque<animal> barn_type;
- barn_type barn;
- #if !defined(BOOST_NO_CXX11_SMART_PTR) && !(defined(BOOST_MSVC) && BOOST_MSVC == 1600) && !BOOST_WORKAROUND(BOOST_GCC, < 40600)
- typedef std::unique_ptr<barn_type> raii_ptr;
- #else
- typedef std::auto_ptr<barn_type> raii_ptr;
- #endif
- //
- // An error type
- //
- struct farm_trouble : public std::exception { };
- public:
- //
- // We would like to make it possible to
- // iterate over the animals in the farm
- //
- typedef barn_type::iterator animal_iterator;
- //
- // We also need to count the farm's size...
- //
- typedef barn_type::size_type size_type;
-
- //
- // And we also want to transfer an animal
- // safely around. The easiest way to think
- // about '::auto_type' is to imagine a simplified
- // 'std::auto_ptr<T>' ... this means you can expect
- //
- // T* operator->()
- // T* release()
- // deleting destructor
- //
- // but not more.
- //
- typedef barn_type::auto_type animal_transport;
- //
- // Create an empty farm.
- //
- farm() { }
-
- //
- // We need a constructor that can make a new
- // farm by cloning a range of animals.
- //
- farm( animal_iterator begin, animal_iterator end )
- :
- //
- // Objects are always cloned before insertion
- // unless we explicitly add a pointer or
- // use 'release()'. Therefore we actually
- // clone all animals in the range
- //
- barn( begin, end ) { }
-
- //
- // ... so we need some other function too
- //
- animal_iterator begin()
- {
- return barn.begin();
- }
- animal_iterator end()
- {
- return barn.end();
- }
-
- //
- // Here it is quite ok to have an 'animal*' argument.
- // The smart container will handle all ownership
- // issues.
- //
- void buy_animal( animal* a )
- {
- barn.push_back( a );
- }
- //
- // The farm can also be in economical trouble and
- // therefore be in the need to sell animals.
- //
- animal_transport sell_animal( animal_iterator to_sell )
- {
- if( to_sell == end() )
- throw farm_trouble();
- //
- // Here we remove the animal from the barn,
- // but the animal is not deleted yet...it's
- // up to the buyer to decide what
- // to do with it.
- //
- return barn.release( to_sell );
- }
- //
- // How big a farm do we have?
- //
- size_type size() const
- {
- return barn.size();
- }
- //
- // If things are bad, we might choose to sell all animals :-(
- //
- raii_ptr sell_farm()
- {
- return barn.release();
- }
- //
- // However, if things are good, we might buy somebody
- // else's farm :-)
- //
- void buy_farm( raii_ptr other )
- {
- //
- // This line inserts all the animals from 'other'
- // and is guaranteed either to succeed or to have no
- // effect
- //
- barn.transfer( barn.end(), // insert new animals at the end
- *other ); // we want to transfer all animals,
- // so we use the whole container as argument
- //
- // You might think you would have to do
- //
- // other.release();
- //
- // but '*other' is empty and can go out of scope as it wants
- //
- BOOST_ASSERT( other->empty() );
- }
-
- }; // class 'farm'.
- int main()
- {
- //
- // First we make a farm
- //
- farm animal_farm;
- BOOST_ASSERT( animal_farm.size() == 0u );
-
- animal_farm.buy_animal( new pig("Betty") );
- animal_farm.buy_animal( new pig("Benny") );
- animal_farm.buy_animal( new pig("Jeltzin") );
- animal_farm.buy_animal( new cow("Hanz") );
- animal_farm.buy_animal( new cow("Mary") );
- animal_farm.buy_animal( new cow("Frederik") );
- BOOST_ASSERT( animal_farm.size() == 6u );
- //
- // Then we make another farm...it will actually contain
- // a clone of the other farm.
- //
- farm new_farm( animal_farm.begin(), animal_farm.end() );
- BOOST_ASSERT( new_farm.size() == 6u );
- //
- // Is it really clones in the new farm?
- //
- BOOST_ASSERT( new_farm.begin()->name() == "Betty" );
-
- //
- // Then we search for an animal, Mary (the Crown Princess of Denmark),
- // because we would like to buy her ...
- //
- typedef farm::animal_iterator iterator;
- iterator to_sell;
- for( iterator i = animal_farm.begin(),
- end = animal_farm.end();
- i != end; ++i )
- {
- if( i->name() == "Mary" )
- {
- to_sell = i;
- break;
- }
- }
- farm::animal_transport mary = animal_farm.sell_animal( to_sell );
- if( mary->speak() == muuuh )
- //
- // Great, Mary is a cow, and she may live longer
- //
- new_farm.buy_animal( mary.release() );
- else
- //
- // Then the animal would be destroyed (!)
- // when we go out of scope.
- //
- ;
- //
- // Now we can observe some changes to the two farms...
- //
- BOOST_ASSERT( animal_farm.size() == 5u );
- BOOST_ASSERT( new_farm.size() == 7u );
- //
- // The new farm has however underestimated how much
- // it cost to feed Mary and its owner is forced to sell the farm...
- //
- animal_farm.buy_farm( new_farm.sell_farm() );
- BOOST_ASSERT( new_farm.size() == 0u );
- BOOST_ASSERT( animal_farm.size() == 12u );
- }
|