BOOST Libraries
// Use the boost auto link feature which automatically chooses // the correct library version #define BOOST_LIB_NAME boost_unit_test_framework #include <boost/config/auto_link.hpp>
Anwendungsbeispiel boost::condition
//shared data definitions (e.g. class attributes) boost::mutex m_mutex; boost::condition m_condition; // within Thread A boost::mutex::scoped_lock lock(m_mutex); // start some action to be executed within another thread B // now wait until the other thread is ready, // i.e. the condition becomes true m_condition.wait(lock); // the lock will be released before blocking // when wait returns the mutex has been locked again // within Thread B // Before starting the action wait until Thread A has entered wait() boost::mutex::scoped_lock lock(m_mutex); // execute some action // inform thread A that we are ready here m_condition.notify_one(); // unlock mutex (e.g. automatically at end of function scope)
Definition SyncUtils::WaitableCondition
// Possible implementation for class WaitableCondition
class WaitableCondition : private boost::noncopyable
{
public:
// Constructor
WaitableCondition (bool in_autoReset = true)
:
m_autoReset (in_autoReset),
m_condIsTrue (false)
{}
// Set and reset the condition
void Set (bool in_state)
{
boost::mutex::scoped_lock lock(m_mutex);
m_condIsTrue = in_state;
if (m_condIsTrue ) m_condition.notify_one();
}
// Check condition without waiting
bool IsTrue (void)
{
boost::mutex::scoped_lock lock(m_mutex);
return m_condIsTrue;
}
// Wait until condition becomes true
// If the condition has already been set the function
// will immediately return without calling boost-wait().
void WaitUntilTrue (void)
{
boost::mutex::scoped_lock lock(m_mutex);
if (!m_condIsTrue)
{
// we really have to wait until someone calls
// Set(true)
m_condition.wait(lock);
}
if (m_autoReset) m_condIsTrue = false;
}
// Wait until condition becomes true (return true)
// or the given timeout has elapsed (return false)
bool TimedWaitUntilTrue (long in_timeoutMs)
{
boost::mutex::scoped_lock lock(m_mutex);
if (!m_condIsTrue)
{
boost::xtime timeInterval =
ConvertFromMilliSec(in_timeoutMs);
if (!m_condition.timed_wait(lock, timeInterval)
return false;
}
if (m_autoReset) m_condIsTrue = false;
return true;
}
private:
bool m_autoReset;
bool m_condIsTrue;
boost::mutex m_mutex;
boost::condition m_condition;
}
Anwendungsbeispiel SyncUtils::WaitableCondition
//shared data definitions (e.g. class attributes) SyncUtils::WaitableCondition m_condition; // within Thread A // start some action to be executed within another thread B // or assume that someone else has done this or will do this // simply wait until the condition has become true m_condition.WaitUntilTrue(); // within Thread B // execute some action // now set the condition m_condition.Set(true);
{ boost::scoped_ptr<std::string> sp(new std::string(“Hallo”)); // Check for existence and print the value if (sp) std::cout << *sp << ‘\n’; // Get the size of the string size_t i = sp->size(); // Change the value of the string *sp = “New text”; } // sp destrucor deletes the string
Wichtig: die verwalteten Objekte müssen durchgängig als shared_ptr weitergegeben werden. Würde ein Objekt zwischendurch als raw pointer behandelt und an anderer Stelle wieder in einen (dann unabhängigen) neuen shared_ptr zur Verwaltung gegeben, so würde dieser SmartPtr von einem falschen Referenzcount ausgehen und unabhängig von den anderwo zu diesem Objekt existierenden SmartPointern das Objekt abbauen.
besondere Funktionalitäten:
Vorteil: this kann wie ein SmartPtr behandelt werden.
Der ReferenzCount kann z.B. über folgende Basisklasse zur Verfügung gestellt werden:
class RefCount { int m_refCount; public: RefCount() : m_refCount(0){} virtual ~RefCount(){} // directly implement the needed free functions here in the scope // of this base class (multithreading not yet considered!) friend void intrusive_ptr_add_ref(RefCount* in_p) {++in_p_>m_refCount;} friend void intrusive_ptr_release(RefCount* in_p) {if (--in_p_>m_refCount==0) delete in_p;} }
numeric_cast (Überwachung des Wertebereiches)
long val = 7; char c = boost::numeric_cast<char>(val); // ok val = 257; c = boost::numeric_cast<char>(val); // exception bad_numeric_cast is thrown here unsigned int ui; int i = -12; ui = boost::numeric_cast<int>(ui); // exception bad_numeric_cast is thrown here
lexical_cast
// string to int std::string s=”43”; int i = boost::lexical_cast<int>(s); // float to string float f= 3.14; s=boost::lexical_cast<std::string>(f); // failed conversion s=”Text without numbers”; i=boostlexial_cast<int>(s); // -> exception bad_lexical_cast // A simple converter function to string which allows // more readable calls template <typename T> std::string ToString (const T& arg) { try {return boost::lexical_cast<std::string>(arg);} catch(boost::bad_lexical_cast& e) {return “”;} } // Usage std::string s=ToString(412);
BOOST_STATIC_ASSERT
// Restricted to compile time expressions, i.e., values and operators // must be known to the compiler // ensure that a template is instantiated only with integer types template <typename T> class MyClass { BOOST_STATIC_ASSERT(boost::is_integral<T>::value); }; // ensure that a template function is used only for a special // range of constant values template <int i> MyFunction() { BOOST_STATIC_ASSERT(i>=1 && i<=10); }
boost::noncopyable
// The following class should not allow copies of itself class MyClass : boost::noncopyable // private inheritance { // declaring copy contructor and assignment operator as private // is no longer necessary };
Konzept less_than_comparable
// concept requirs the implementation of bool operator<(const T&, const T&) class MyClass : boost::less_than_comparable<MyClass> // Barton-Nackman { std:string m_name; public: friend bool operator<(const MyClass& lhs, const MyClass& rhs) {return lhs.m_name < rhs.m_name;} };
Operatoren für verschiedene Typen
// The following string class should also work with the char* type class MyString : boost::addable<MyString, bost::addable2<MyString, const char*> > { public: explicit MyString (const char*); MyString(const MyString&); // Operators to implement MyString operator=(const MyString&); MyString& operator+=(const MyString&); MyString& operator+=(const char*); }; // The base classes add implementation for following operators: // MyString operator+(const MyString&, const MyString&); // MyString operator+(const MyString&, const char*); // MyString operator+(const char*, const MyString&);
Syntax für regular expressions
. = beliebiges Zeichen * = 0 oder beliebig viele Wiederholungen + = beliebig viele Wiederholungen, aber mindestens einmal ? = keine oder genau eine Wiederholung ? = Ziel shortest possible match, als Zuatz zu * oder + \d = Ziffer \w = Wort (besser als [a-zA-Z], da Internationalisierung berücksichtigt \1 = Referenz auf erste gefundene SubExpression {n} = n Wiederholungen {2,4} = 2 bis 3 Wiederholungen {2,} = mindestens 2 Wiederholungen [abc] = Alternativen entweder a oder b oder c [a-c] = Alternativen, abgekürzt als Bereich [^abc] = ungleich a,b,c | = Trenner für Alternativen \A = Beginn des Zeichenpuffers \Z = Ende des Zeichenpuffers Beispiele: // 3 Ziffern, ein Wort aus Buchstaben, ein beliebiges Zeichen, 2 Ziffern // oder „N/A“, ein Leerzeichen dann das erste Wort nochmals boost::regex reg ("\\d{3}(a-zA-Z+).(\\d{2}|N/A)\s\1)");
Searching
// Calculate the number of occurences for new and delete boost::regex reg („(new)|(delete)“); boost::smatch m; std::string s =”Any text containing new and delete..”; int newCounter = 0; int deleteCounter = 0; std::string::const_iterator it = s.begin()=; std::string::const_iterator end = s.end()=; while (boost::regex_search(it,end,m,reg) { // m[1/2] indicates whether new or delete was found m[1].matched ? ++new_counter : ++ deleteCounter; it = m[0].second; // m[0] is a reference to the submatch, continue // searching at the end of that submatch }
Replacing
// Replace colour with color and preserve the found case // i.e. Colour and colour should be treated correctly bost::regex reg (“(Colo)(u)(r)”, // use three subexpressions boost::regex::icase | boost::regex::perl); // ignore case std::string s = “Colour, colours, color, colourize”; // the matched expression is replaced with the // first and third subexpression s=boost::regex_replace(s,reg,”$1$3”);
Elementarbeispiel Any
boost::any a; // Any type can be stored a = std::string(A string”); a = 43; a = 3.14; // accessing the stored value requires to // know the correct type double d = boost::any_cast<double>(a); // Reactions when assuming the wrong type: // using pointer syntax int* pVal = boost::any_cast<int>(&a); // in this case 0 is returned // using const reference int val = boost::any_cast<int>(a); // exception boost::bad_any_cast // Requesting the type and comparing it if (typeid(int)==a.type()) {/* access as int type is possible */}
STL-Container mit heterogenen Elementen
class A{}; class B{}; std::vector<boost::any> vec; // Store arbitrary objects within the vector vec.push_back (A()); vec.push_back (B()); vec.push_back (boost::shared_ptr<B>(new B)); vec.push_back (std::string(“Hallo”)); vec.push_back (4711); vec.push_back (3.14); // Remark: You can build a function to process the elements stored // within the vector. The function simply has to check for the types it // is able to process (e.g. using pointer syntax see above) and leave the // other types unhandled // generic helper function to test the stored type template <typename T> bool Contains (const boost::any& a) {return typeid(T)==a.type();}
Elementarbeispiel variant
// allow three types for your variant typedef boost::variant<int,std::string,double> MyVariant; MyVariant myVar; // default constructed int = first type MyVariant myVar2 (Hello”); // variant containing type string // dynamically change the type myVar2 = 2.53; myVar2 = 47; // accessing the stored values assert(boost::get<int>(myVar2)==47); // wrong type would cause exception boost::bad_get) int* pVal=boost::get<int>(&myVar2); assert(pVal &&(*pVal==47)) // wrong type would cause return of NULL pointer)
Zugriff über Visitor (mit compile time check)
// Define a visitor class containing a function call operator for each // type within your variant you want to access. // Remark: use reference syntax to avoid unwanted conversions (e.g. // from char to int) class PrintVisitor : public boost::static_visitor<void> { public: void operator()(int& i) const {std::cout << “int val “ << i << ‘\n’;} void operator()(double& d) const {std::cout << “double val “ << d << ‘\n’;} }; PrintVisitor v; myVar = 46; boost::apply_visitor(v,myVar); myVar = 4.5; boost::apply_visitor(v,myVar); myVar = “Any text”; boost::apply_visitor(v,myVar); // Compile ERROR, because type string // is not supported by PrintVisitor // Possible extension to PrintVisitor for generically support // of output for all types compatible with << operator class PrintVisitor (see above) { // specific operators for some types see above // generic operator for all other types template <typename T> void operator()(T& t) const {std::cout << t << '\n';} }
tuple - Elementarbeispiel
boost::tuple<int,double,std::string> triple (42, 3.14, “Hello”); // Access the values int i = boost::get<0>(triple); double d = boost::get<1>(triple);
tuple als Returnwert
boost::tuple<int,int> Calculate (int x) {return boost::make_tuple(x+3, x*x);} boost::tuple<int,int> result = Calculate(17); int resultX = result.get<0>(); int resultY = result.get<1>(); // directly connect to result variables boost::tie(resultX, resultY) = Calculate(19); // here the results will be available without further asking; // instead of making copies references are used; // is the same as make_tuple(ref(resultx), ref(resultY) = ..
tuple - generisches Programmieren, for_each
//--- Definition of for_each_element --- // for the last element within the tuple (is always null_type) // do nothing template <typename Function> void for_each_element ( const boost::tuples::null_type&, Function) {} // for the preceeding elements call the given function template <typename Tuple, typename Function> void for_each_element (Tuple& t, Function func) { func(t.get_head()); // call func for the first element for_each_elemnt(t.get_tail(), func); // recursively process // the rest of the tuple } //--- FuncObjects for output --- struct PrintAll { template <typename T> void operator()(const T& t) {std::cout << t <<’\n’;} } template typename T> struct PrintSelectedType { // print the selected type void operator()(const T& t) {std::cout << t <<’\n’;} // ignore all other types (discarding overload) template <typename U> void operator()(const U&){} } //--- Example --- boost::tuple<int,short,double> nums(1,2,3.14); for_each_element(nums,PrintAll()); // writes all numbers for_each_element(nums,PrintSelectedType<double>()); // writes only the // last number