Wilkening-Online Logo

Einführung in Boost



Von Detlef Wilkening
09.03.2012
Version: 4

Hinweis - die erste Version dieses Artikels entspricht den Folien des Vortrags, den ich am 22.02.2012 auf dem 3-ten C++ Treffen in Düsseldorf gehalten habe. Mittlerweile habe ich einzelne Hinweise und neue Informationen eingearbeitet - siehe Versions-Historie.

1. Einführung

Boost - eine Sammlung "freier, portabler, begutachteter" C++ Bibliotheken „Boost ist die Spielwiese der C++ Standardisierer“ „Und wenn man nur die Shared-Pointer von Boost verwendet, so ist die Nutzung von Boost schon sehr sinnvoll“

2. Bibliotheken

2.1 Smart-Pointer


// Beispiel 1 - Smart-Pointer

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
using namespace std;

int main()
{
   typedef boost::shared_ptr<int> int_ptr;
   vector<int_ptr> v1, v2;

   for (int i=0; i<5; ++i)
   {
      int_ptr ptr(new int(i));      // nicht optimal - siehe naechstes Beispiel
      v1.push_back(ptr);
      v2.push_back(ptr);
   }

   cout << "v1: " << v1.size() << " => ";
   for_each(v1.cbegin(), v1.cend(), [](const int_ptr& pn) { cout << *pn << ' '; });
   cout << endl;

   cout << "v2: " << v2.size() << " => ";
   for_each(v2.cbegin(), v2.cend(), [](const int_ptr& pn) { cout << *pn << ' '; });
   cout << endl;
}


Ausgabe:

v1: 5 => 0 1 2 3 4
v2: 5 => 0 1 2 3 4



// Beispiel 2 - Smart-Pointer

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace std;

int main()
{
   typedef boost::shared_ptr<int> int_ptr;
   vector<int_ptr> v1, v2;

   for (int i=0; i<5; ++i)
   {
      int_ptr ptr = boost::make_shared<int>(i);            // besser
      v1.push_back(ptr);
      v2.push_back(ptr);
   }

   cout << "v1: " << v1.size() << " => ";
   for_each(v1.cbegin(), v1.cend(), [](const int_ptr& pn) { cout << *pn << ' '; });
   cout << endl;

   cout << "v2: " << v2.size() << " => ";
   for_each(v2.cbegin(), v2.cend(), [](const int_ptr& pn) { cout << *pn << ' '; });
   cout << endl;
}


Ausgabe:

v1: 5 => 0 1 2 3 4
v2: 5 => 0 1 2 3 4

2.2 Pointer-Container


// Beispiel 3 - Pointer-Container

#include <iostream>
#include <boost/ptr_container/ptr_vector.hpp>
using namespace std;

int main()
{
   boost::ptr_vector<int> v;

   v.push_back(new int(11));                       // Hinzufuegen mit einem Zeiger
   v.push_back(new int(22));
   v.push_back(new int(33));

   cout << v[0] << endl;                           // Aber normale Nutzung
   cout << v[1] << endl;
   cout << v[2] << endl;

   cout << "v: " << v.size() << " => ";
   boost::ptr_vector<int>::const_iterator it = v.begin();
   for (; it!=v.end(); ++it)
   {
      cout << *it << ' ';                          // Auch hier normale Nutzung
   }
   cout << endl;

   cout << "Lambda => ";
   for_each(v.cbegin(), v.cend(), [](int n) { cout << n << ' '; });       // Und auch hier
   cout << endl;
}


Ausgabe:

11
22
33
v: 3 => 11 22 33
Lambda => 11 22 33

2.3 String-Algorithm


// Beispiel 4 - String-Algorithm 1

#include <iostream>
#include <string>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/trim.hpp>
using namespace std;

int main()
{
   string s("  ABC-123-def ");
   cout << '"' << s << "\"\n";

   string sl(boost::algorithm::to_lower_copy(s));
   cout << '"' << sl << "\"\n";

   string su(boost::algorithm::to_upper_copy(s));
   cout << '"' << su << "\"\n";

   string st(boost::algorithm::trim_copy(s));
   cout << '"' << st << "\"\n";

   boost::algorithm::to_lower(s);
   cout << '"' << s << "\"\n";

   boost::algorithm::to_upper(s);
   cout << '"' << s << "\"\n";

   boost::algorithm::trim(s);
   cout << '"' << s << "\"\n";
}


Ausgabe:

"  ABC-123-def "
"  abc-123-def "
"  ABC-123-DEF "
"ABC-123-def"
"  abc-123-def "
"  ABC-123-DEF "
"ABC-123-DEF"



// Beispiel 5 - String-Algorithm 2

#include <iostream>
#include <iostream>
#include <string>
#include <boost/algorithm/string/replace.hpp>
using namespace std;

int main()
{
   string s("C++ ist toll und C++ ist gut");
   cout << s << endl;

   boost::algorithm::replace_all(s, " ", "__");
   cout << s << endl;
}


Ausgabe:

C++ ist toll und C++ ist gut
C++__ist__toll__und__C++__ist__gut



// Beispiel 6 - String-Algorithm 3

#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
using namespace std;

int main()
{
   string s("Hallo 7,-Ich lerne-jetzt 9*C++.");
   cout << s << endl;

   vector<string> v;
   boost::algorithm::split(v, s, boost::algorithm::is_any_of(" -*"));

   for (vector<string>::iterator it=v.begin(); it!=v.end(); ++it)
   {
      cout << '\'' << *it << "'\n";
   }
}


Ausgabe:

Hallo 7,-Ich lerne-jetzt 9*C++.
'Hallo'
'7,'
'Ich'
'lerne'
'jetzt'
'9'
'C++.'



// Beispiel 7 - String-Algorithm 4

#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
using namespace std;

int main()
{
   string s("Hallo 7,-Ich lerne-jetzt 9*C++.");
   cout << s << endl;

   vector<string> v;
   boost::algorithm::split(v, s, boost::algorithm::is_digit());

   for (vector<string>::iterator it=v.begin(); it!=v.end(); ++it)
   {
      cout << "-> '" << *it << "'\n";
   }
}


Ausgabe:

Hallo 7,-Ich lerne-jetzt 9*C++.
-> 'Hallo '
-> ',-Ich lerne-jetzt '
-> '*C++.'

2.4 Assign


// Beispiel 8 - Assign 1

#include <vector>
#include <iostream>
using namespace std;

int main()
{
   vector<int> v;
   v.push_back(1);                                  // furchtbar...
   v.push_back(5);
   v.push_back(9);
   v.push_back(12);

   vector<int>::const_iterator it = v.begin();
   for (; it!=v.end(); ++it)
   {
      cout << *it << ' ';
   }
   cout << endl;
}


Ausgabe:

1 5 9 12



// Beispiel 9 - Assign 2

#include <vector>
#include <iostream>
#include <boost/assign/list_of.hpp>
using namespace std;
using namespace boost::assign;

int main()
{
   vector<int> v = list_of(1)(5)(9)(12);

   vector<int>::const_iterator it = v.begin();
   for (; it!=v.end(); ++it)
   {
      cout << *it << ' ';
   }
   cout << endl;
}


Ausgabe:

1 5 9 12



// Beispiel 10 - Assign 3

#include <vector>
#include <iostream>
#include <boost/assign/list_of.hpp>
using namespace std;
using namespace boost::assign;

int main()
{
   vector<int> v = list_of(1).repeat(11, 2)(3);

   vector<int>::const_iterator it = v.begin();
   for (; it!=v.end(); ++it)
   {
      cout << *it << ' ';
   }
   cout << endl;
}


Ausgabe:

1 2 2 2 2 2 2 2 2 2 2 2 3



// Beispiel 11 - Assign 4

#include <iostream>
#include <string>
#include <map>
#include <boost/assign/list_of.hpp>
using namespace std;
using namespace boost::assign;

int main()
{
   map<int, string> m = map_list_of(1, "Max")(3, "Jan")(2, "Ina");
   for (map<int, string>::const_iterator it=m.begin(); it!=m.end(); ++it)
   {
      cout << it->first << " -> " << it->second << '\n';
   }
}


Ausgabe:

1 -> Max
2 -> Ina
3 -> Jan

2.5 Bind


// Beispiel 12 - Bind

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/bind.hpp>
using namespace std;

bool myless(int n1, int n2)
{
   return n1<n2;
}

int main()
{
   vector<int> v;
   v.push_back(1);
   v.push_back(2);
   v.push_back(7);
   v.push_back(11);
   v.push_back(13);

   cout << "v:";
   for_each(v.cbegin(), v.cend(), [](int n) { cout << ' ' << n; });
   cout << '\n';

   int n4 = count_if(v.begin(), v.end(), boost::bind(myless, _1, 4));
   cout << "Anzahl Werte kleiner als 4: " << n4 << '\n';

   int n8 = count_if(v.begin(), v.end(), boost::bind(myless, _1, 8));
   cout << "Anzahl Werte kleiner als 8: " << n8 << endl;
}


Ausgabe:

v: 1 2 7 11 13
Anzahl Werte kleiner als 4: 2
Anzahl Werte kleiner als 8: 3

2.6 Boost Lambda Library (BLL)


// Beispiel 13 - Boost Lambda Library (BLL)

#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/assign/list_of.hpp>
#include <boost/lambda/lambda.hpp>
using namespace std;
using namespace boost::assign;
using namespace boost::lambda;

int main()
{
   vector<int> v = list_of(5)(1)(3)(4)(6)(2);           // Nutzung von Boost.Assign (s.o.)

   for_each(v.begin(), v.end(), cout << _1 << ' ');
   cout << '\n';

   sort(v.begin(), v.end(), _1>_2);

   for_each(v.begin(), v.end(), cout << _1 << ' ');
   cout << '\n';
}


Ausgabe:

5 1 3 4 6 2
6 5 4 3 2 1

2.7 Date-Time


// Beispiel 14 - Date-Time

#include <iostream>
#include "boost/date_time/posix_time/posix_time.hpp"
using namespace std;
using namespace boost::posix_time;
using namespace boost::gregorian;

int main()
{
   ptime now = second_clock::local_time();
   cout << "Jetzt:       " << now << '\n';

   date today = now.date();
   cout << "Heute:       " << today << '\n';

   date tommorrow = today + days(1);
   cout << "Morgen:      " << tommorrow << '\n';

   date day_after_tom = today + days(2);
   cout << "Uebermorgen: " << day_after_tom << '\n';

   ptime midnight(tommorrow);
   cout << "Mitternacht: " << midnight << '\n';

   time_iterator titr(now, hours(1));
   for (int i=0; titr<midnight; ++titr)
   {
      cout << "Jetzt + " << i++ << " h: " << *titr << '\n';
   }

   time_duration remaining = midnight - now;
   cout << "Sie haben noch " << remaining << " Std:Min:Sek bis Mitternacht...\n";
}


Mögliche Ausgabe (nur "möglich" wegen Datum/Zeit-Abhängigkeit):


Jetzt:       2012-Feb-22 17:52:42
Heute:       2012-Feb-22
Morgen:      2012-Feb-23
Uebermorgen: 2012-Feb-24
Mitternacht: 2012-Feb-23 00:00:00
Jetzt + 0 h: 2012-Feb-22 17:52:42
Jetzt + 1 h: 2012-Feb-22 18:52:42
Jetzt + 2 h: 2012-Feb-22 19:52:42
Jetzt + 3 h: 2012-Feb-22 20:52:42
Jetzt + 4 h: 2012-Feb-22 21:52:42
Jetzt + 5 h: 2012-Feb-22 22:52:42
Jetzt + 6 h: 2012-Feb-22 23:52:42
Sie haben noch 06:07:18 Std:Min:Sek bis Mitternacht...

2.8 Random


// Beispiel 15 - Random 1

#include <iostream>
#include <ctime>
#include <boost/random.hpp>
using namespace std;

int main()
{
   boost::minstd_rand generator(static_cast<unsigned int>(time(0)));
   boost::uniform_int<> distribution(1, 6);

   for(int i=0; i<10; ++i)
   {
      cout << distribution(generator) << ' ';
   }
   cout << '\n';
}


Mögliche Ausgabe (nur "möglich" wegen Zufallszahlen):

6 1 1 5 5 2 3 4 3 3



// Beispiel 16 - Random 2

#include <iostream>
#include <ctime>
#include <boost/random.hpp>
using namespace std;
using namespace boost;

int main()
{
   minstd_rand generator(static_cast<unsigned int>(time(0)));
   uniform_int<> distribution(1, 6);
   variate_generator<minstd_rand&, uniform_int<>> die(generator, distribution);

   for(int i=0; i<10; ++i)
   {
      cout << die() << ' ';
   }
   cout << '\n';
}


Mögliche Ausgabe (nur "möglich" wegen Zufallszahlen):

6 3 2 5 6 3 3 3 4 3

2.9 Filesystem


// Beispiel 17 - Filesystem

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
   directory_iterator it("c:\\");
   directory_iterator eit;
   for (; it!=eit; ++it)
   {
      if (is_directory(it->status()))
      {
         cout << "D: ";
      }
      else
      {
         cout << "   ";
      }
      cout << it->path() << '\n';
   }
}


Mögliche Ausgabe (nur "möglich" wegen individuellen Dateisystems):

D: "c:\$RECYCLE.BIN"
   "c:\Documents and Settings"
   "c:\hiberfil.sys"
D: "c:\Intel"
   "c:\pagefile.sys"
D: "c:\Program Files"
D: "c:\Recovery"
D: "c:\System Volume Information"
D: "c:\Users"
D: "c:\Windows"

2.10 Regex


// Beispiel 18 - Regex

#include <string>
#include <iostream>
#include <boost/regex.hpp>
using namespace std;
using namespace boost;

int main()
{
   regex x("Hal{2,}o");

   string s0 = "Hao";
   string s1 = "Halo";
   string s2 = "Hallo";
   string s3 = "Halllo";
   string s4 = "Hallllo";

   cout << s0 << ": " << regex_match(s0, x) << '\n';
   cout << s1 << ": " << regex_match(s1, x) << '\n';
   cout << s2 << ": " << regex_match(s2, x) << '\n';
   cout << s3 << ": " << regex_match(s3, x) << '\n';
   cout << s4 << ": " << regex_match(s4, x) << '\n';
}


Ausgabe:

Hao: 0
Halo: 0
Hallo: 1
Halllo: 1
Hallllo: 1

2.11 Serialization


// Beispiel 19 - Serialization 1

#include <fstream>
#include <iostream>
#include <string>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
using namespace std;
using namespace boost::archive;

class person
{
   friend class boost::serialization::access;

public:
   person() : size(0) {}
   person(const string& n, int s) : name(n), size(s) {}

   friend ostream& operator<<(ostream& os, const person& p)
   {
      return os << p.name << " - " << p.size << " cm";
   }

private:
   template<class Archive> void serialize(Archive& ar, const unsigned int version)
   {
      ar & name;
      ar & size;
   }

   string name;
   int size;
};


int main()
{
   {
      const person axel("Axel", 182);
      cout << axel << '\n';

      ofstream ofs("person.txt");
      text_oarchive oa(ofs);
      oa << axel;
   }

   {
      person newperson;
      ifstream ifs("person.txt", ios::binary);
      boost::archive::text_iarchive ia(ifs);
      ia >> newperson;
      cout << newperson << '\n';
   }
}


Ausgabe:

Axel - 182 cm
Axel - 182 cm


Inhalt von Datei "person.txt":

22 serialization::archive 9 0 0 4 Axel 182



// Beispiel 20 - Serialization 2

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
using namespace std;
using namespace boost::archive;

class person
{
   friend class boost::serialization::access;

public:
   person() : size(0) {}
   person(const string& n, int s) : name(n), size(s) {}
   person(const string& n, int s, const string& m1) : name(n), size(s)
   {
      mails.push_back(m1);
   }
   person(const string& n, int s, const string& m1, const string& m2) : name(n), size(s)
   {
      mails.push_back(m1);
      mails.push_back(m2);
   }

   friend ostream& operator<<(ostream& os, const person& p)
   {
      os << p.name << " - " << p.size << " cm\n";
      for_each(p.mails.cbegin(), p.mails.cend(),
         [](const string& adr) { cout << "- " << adr << '\n'; }
      );
      return os;
   }

private:
   template<class Archive> void serialize(Archive& ar, const unsigned int version)
   {
      ar & name;
      ar & size;
      ar & mails;
   }

   string name;
   int size;
   vector<string> mails;
};


int main()
{
   {
      const person axel("Axel", 182, "axel@axel.de", "ax@test.de");
      cout << axel << '\n';

      ofstream ofs("person.txt");
      text_oarchive oa(ofs);
      oa << axel;
   }

   {
      person newperson;
      ifstream ifs("person.txt", ios::binary);
      boost::archive::text_iarchive ia(ifs);
      ia >> newperson;
      cout << newperson << '\n';
   }
}


Ausgabe:

Axel - 182 cm
- axel@axel.de
- ax@test.de

Axel - 182 cm
- axel@axel.de
- ax@test.de


Inhalt von Datei "person.txt":

22 serialization::archive 9 0 0 4 Axel 182 0 0 2 0 12 axel@axel.de 10 ax@test.de



// Beispiel 21 - Serialization 3

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
using namespace std;
using namespace boost::archive;

class person
{
   friend class boost::serialization::access;

public:
   person() : size(0) {}
   person(const string& n, int s) : name(n), size(s) {}
   person(const string& n, int s, const string& m1) : name(n), size(s)
   {
      mails.push_back(m1);
   }
   person(const string& n, int s, const string& m1, const string& m2) : name(n), size(s)
   {
      mails.push_back(m1);
      mails.push_back(m2);
   }

   friend ostream& operator<<(ostream& os, const person& p)
   {
      os << p.name << " - " << p.size << " cm\n";
      for_each(p.mails.cbegin(), p.mails.cend(),
         [](const string& adr) { cout << "- " << adr << '\n'; }
      );
      return os;
   }

private:
   template<class Archive> void serialize(Archive& ar, const unsigned int version)
   {
      ar & BOOST_SERIALIZATION_NVP(name);
      ar & BOOST_SERIALIZATION_NVP(size);
      ar & BOOST_SERIALIZATION_NVP(mails);
   }

   string name;
   int size;
   vector<string> mails;
};


int main()
{
   {
      const person axel("Axel", 182, "axel@axel.de", "ax@test.de");
      cout << axel << '\n';

      ofstream ofs("person.xml.txt");
      xml_oarchive oa(ofs);
      oa << BOOST_SERIALIZATION_NVP(axel);
   }

   {
      person newperson;
      ifstream ifs("person.xml.txt", ios::binary);
      boost::archive::xml_iarchive ia(ifs);
      ia >> BOOST_SERIALIZATION_NVP(newperson);
      cout << newperson << '\n';
   }
}


Ausgabe:

Axel - 182 cm
- axel@axel.de
- ax@test.de

Axel - 182 cm
- axel@axel.de
- ax@test.de


Inhalt von Datei "person.xml.txt":

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<axel class_id="0" tracking_level="0" version="0">
   <name>Axel</name>
   <size>182</size>
   <mails class_id="1" tracking_level="0" version="0">
      <count>2</count>
      <item_version>0</item_version>
      <item>axel@axel.de</item>
      <item>ax@test.de</item>
   </mails>
</axel>
</boost_serialization>

2.12 Thread


// Beispiel 22 - Thread

#include <iostream>
#include <boost/thread.hpp>
using namespace std;

void doit(const char* name, int ms)
{
   for (int i=0; i<6; ++i)
   {
      boost::this_thread::sleep(boost::posix_time::millisec(ms));

      // Achtung - Ausgabe muesste eigentlich MT geschuetzt sein
      // Hier im Beispiel geht es aufgrund der gewaehlten Sleep-Zeiten auch so
      cout << name << ": " << i << endl;
   }
}

int main()
{
   boost::thread t1(doit, "Thread 1",  500);
   boost::thread t2(doit, "Thread 2", 1130);
   t1.join();
   t2.join();
}


Ausgabe:

Thread 1: 0
Thread 1: 1
Thread 2: 0
Thread 1: 2
Thread 1: 3
Thread 2: 1
Thread 1: 4
Thread 1: 5
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5

2.13 Spirit


// Beispiel 23 - Spirit 1

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
using namespace std;
using boost::spirit::qi::int_;
using boost::spirit::qi::phrase_parse;
using boost::spirit::ascii::space;

int main()
{
   string s("1, 2,34     ,     17  ");
   string::const_iterator it = s.cbegin();
   string::const_iterator eit = s.cend();

   bool res = phrase_parse(it, eit, int_ >> *(',' >> int_), space);

   cout << "res:  " << boolalpha << res << endl;
   cout << "full: " << boolalpha << (it==eit) << endl;
}


Ausgabe:

res:  true
full: true



// Beispiel 24 - Spirit 2

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
using namespace std;

int main()
{
   using boost::spirit::qi::_1;
   using boost::spirit::qi::int_;
   using boost::spirit::qi::phrase_parse;
   using boost::spirit::ascii::space;
   using boost::phoenix::ref;

   string s("1, 2,34     ,     17  ");
   string::const_iterator it = s.cbegin();
   string::const_iterator eit = s.cend();

   int n = 0;

   bool res = phrase_parse(it, eit, int_[ref(n) = _1] >> *(',' >> int_[ref(n) += _1]), space);

   cout << "res:  " << boolalpha << res << endl;
   cout << "full: " << boolalpha << (it==eit) << endl;
   cout << "n: " << n << endl;
}


Ausgabe:

res:  true
full: true
n: 54

2.14 Weitere

3. Ausblick

4. Fazit

Beteiligen Sie sich

5. Literatur

6. Links

7. Versions-Historie

Die Versions-Historie dieses Artikels:
Schlagwörter: