C++ Standard Library: <exception>, <thread>, <regex>, <random> Ben Morgan

advertisement
C++ Standard Library:
<exception>, <thread>,
<regex>, <random>
Ben Morgan
A Whistlestop Tour of …
• <regex> for Pattern Matching of Strings
• <random> for Random Number Generation/Distribution
• <exception> for Exception Handling
•Cleaner and simpler error handling, with a catch…
• <thread> and others for Concurrent Computing
•Several computations executing at same time
Regular Expressions With <regex>
Regular Expressions
• A Domain Specific Language to describe and perform
Pattern Matching within sequences of characters
• https://en.wikipedia.org/wiki/Regular_expression
• Many use cases, but three major ones
• Check if a string matches a given pattern
• Find all substrings of a string that match a pattern
• Replace matching substrings with another string
<regex>
• C++11 has the <regex> library with classes and
functions for using RegExps in code, with
• std::regex class for defining a RegExp
• std::regex_match function(s) for matching entire
string
• std::regex_search function(s) for matching any
part of string
• std::regex_replace function(s) for replacing
matches with another string
std::regex
#include <regex>
int main(int, char**) {
std::regex alnumRegex("[A-Z0-9]+");
return 0;
}
“Sequence of 1 or more
characters in the ranges
A-Z and 0-9”
std::regex_match
#include <regex>
#include <iostream>
int main(int, char**) {
std::regex alnumRegex("[A-Z0-9]+");
std::string foo("TH1SMATCH3S");
std::string bar("TH!Sis Bad?");
std::cout << std::regex_match(foo, alnumRegex) << "\n";
std::cout << std::regex_match(bar, alnumRegex) << "\n";
return 0;
}
Should print 1 then 0
std::regex_replace
#include <regex>
#include <iostream>
“Any character not in
the ranges A-Z and 0-9”
int main(int, char**) {
std::regex removeRegex(“[^A-Z0-9]");
std::string foo(“EATS, SHOOT’S AND LEAVES");
std::cout << std::regex_search(foo,
removeRegex,
"")
<< "\n";
return 0;
}
<regex>
• Refer to the cppreference documents for more of using
regex:
• http://en.cppreference.com/w/cpp/regex
• Lots more than can be done, including
• Extraction of matching substrings
• Different RegExp grammars
• Worth learning about Regular Expressions anyway, as
they are used extensively in computing!
Example
https://github.com/mpags-cpp/mpags-cpp-extra
Random Numbers With <random>
Pseudo-Random Number Generation
• Most scientific software makes use of random number
generation at some level
• https://en.wikipedia.org/wiki/
Random_number_generation
• Generally you should use the interfaces provided by the
framework of your project to guarantee consistent and
reliable behaviour.
• If required, C++11 does provide a reasonable set of
classes in the <random> library
<random>
• C++11 divides random number generation into three
main areas • Creating seeds (initialization) for the generator
• Uniform random number generation in a range
• Provides Mersenne Twister and RANLUX “engines”
• Random number distributions
• Uses output of “engine”, returns random numbers
drawn from, e.g. Normal Distribution
<random>
#include <random>
#include <list>
#include <iostream>
int main(int, char**) {
std::random_device seeder; // (May) use hardware to create seed value
std::mt19937 engine(seeder()); //Mersenne Twister, with seed from seeder
std::normal_distribution<> gauss(1.23, 2.5); // Normal, mu=1, sigma=2.5
std::list<double> data;
std::generate_n(std::back_inserter(data), 1000000,
[&gauss, &engine](){return gauss(engine);});
double mu {std::accumulate(data.begin(), data.end(), 0.0)/data.size()};
std::cout << "Mean : " << mu << "\n";
return 0;
}
Error Handling with Exceptions
Error Handling in mpags-cipher
• In mpags-cipher we had several cases where we
needed to handle errors
• Bad command line input
• Invalid Cipher Key
• Errors were indicated using bool returns, but
• That doesn’t provide much information on the cause
• Can happily ignore the return value…
throwing Exceptions
• An exception is nothing exceptional - it can be any
object that is Copyable or Movable.
• Exceptions are created (“raised, thrown”) using the
throw keyword followed by the object to “throw”
int foo() {
…
throw true;
…
return 42;
}
int main(int, char**) {
int answer {foo()};
return 0;
}
Exception Propagation
• A throw results in quite different behaviour to a return
• The thrown object is passed “up the stack” of calls until
it is handled.
• When handled, the stack is “unwound” with destructors
of any fully created objects invoked.
• If the exception is never handled, it passes out of main,
resulting in an immediate termination.
• In this case, whether destructors are invoked is
implementation defined.
Exception Propagation
int bar() {
BObject b {};
throw true;
return 1;
}
int foo() {
AObject a {};
bar();
return 42;
}
int main(int, char**) {
int answer {foo()};
return 0;
}
Stack Before throw:
BObject::BObject()
bar()
AObject::AObject()
foo()
main()
On Stack Unwind, call
BObject::~BObject()
AObject::~AObject()
catching Exceptions
• To handle exceptions, we wrap code that may emit
them in a try/catch block.
• The catch parts specify the types of exception object
this block can handle (any others propagate further)
int main(int, char**) {
try {
somethingThatMightThrow();
} catch (bool& e) { //Catch by reference to avoid slicing
std::cout << “Handling bool exception\n”;
} catch (int& e) {
std::cout << “Handling int exception\n”;
}
return 0;
}
<exception>
• Header that provides the std::exception base class,
plus several generic concrete classes, e.g.
• std::logic_error,
std::runtime_error
• Best to implement exception types specific to the
project, e.g. for mpags-cipher, could have
struct CommandLineParseError{};
struct InvalidCommandLineArgument{};
struct InvalidCipherKey{};
• In effect, we use the type to decide how to handle the
error.
Traps and Pitfalls
• Though exceptions offer an easy error handling
mechanism, their use does require a bit of care
because of the stack unwinding
• For example, if you’ve new’d an object then throw, the
object won’t be deleted (memory leak)
• Using Smart Pointers helps here!
• Exception Safety: ensuring that an object isn’t
corrupted when one of its member functions throws.
Further Reading
• The two best starting points for Exceptions in C++ are
the Super FAQ and Core Guidelines:
• https://isocpp.org/faq
• https://github.com/isocpp/CppCoreGuidelines
• Also see
• http://exceptionsafecode.com
Example
https://github.com/
mpags-cpp/mpags-cppextra
Concurrent Programming in C++11
Concurrency
• Can no longer rely on processor clock speed for
increasing computational throughput - instead, split
tasks across N>1 parallel “things”
• Several levels of parallelism
• SIMD or “vectorization” (on chip)
• Multithread/Multicore (single machine)
• Multiprocessor (multiple machine)
Concurrency in Action
• Even something as simple as Web Browser uses
concurrency:
• You download a file - this happens in a separate
thread.
• Means you can continue browsing while the file
downloads in the background.
• The browser may download updates for itself in the
background (Chrome for example)
Concurrency in C++11
• Prior to C++11, concurrent programming relied on the
underlying OS implementation (pthreads on UNIX,
CreateThread on Windows)
• C++11 introduced the thread support library which
provide a cross-platform API hiding the underlying
implementation.
• Provides all of the main abstractions of multithreading
in a series of headers:
• http://en.cppreference.com/w/cpp/thread
std::async and std::future
• C++11 provides both high and low level thread
creation/management interfaces (cf new/delete vs
make_shared/make_unique for memory)
• We’ll only look at the high level interface:
• std::async : Takes a function that will be run
asynchronously, returns a std::future instance
that will hold the result of the function call.
• std::future : Wraps result of an asynchronous
operation. Provides interface to query, wait for or get
result of the operation.
Example
https://github.com/
mpags-cpp/mpags-cppextra
Traps and Pitfalls
• Concurrent programming requires more thought
because data (Objects) can be shared between threads
• For example, what happens if two threads try to add
data into the same std::vector instance at the same
time?
• Since computations may be performed out of
sequence, synchronisation may be needed.
• The good news is that designing code for concurrency
generally results in cleaner and more coherent code!
Further Reading
• For C++, a good
reference is Anthony
Wiliams’ book:
• For more general guides
to structuring concurrent
algorithms:
Download