Boost源码分析笔记

Recently, I’ve been reading the Boost code and writing some analyses on the usage and implementation of useful modules in the Boost libraries, with updates to come periodically.

Note: When using Boost, don’t be lazy and directly use using namespace std;, as there are many name collisions with the standard library, and the introduction of namespace is precisely to solve this problem. Reasonable and correct use of namespaces is what a qualified cpp programmer should do.

Timer

The current version of Boost (1.62) includes two versions of timer: one is timer (v1), which is implemented using C/C++ library functions and provides low precision (relying on the operating system or compiler); the timer does not require linking libraries, just include <boost/timer.hpp>; the second is cpu_timer (v2), which uses the API of the operating system based on the chrono library, offering higher precision timing.

timer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <boost/timer.hpp>

using namespace std;
using namespace boost;

int main(int argc,char* argv[])
{
timer t;
cout<<t.elapsed_max()<<endl;
cout<<t.elapsed_min()<<endl;
cout<<t.elapsed()<<endl;
return 0;
}

The timer in Boost is implemented by calling the C/C++ library function clock():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class timer
{
public:
timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
// timer( const timer& src ); // post: elapsed()==src.elapsed()
// ~timer(){}
// timer& operator=( const timer& src ); // post: elapsed()==src.elapsed()
void restart() { _start_time = std::clock(); } // post: elapsed()==0
double elapsed() const // return elapsed time in seconds
{ return double(std::clock() - _start_time) / CLOCKS_PER_SEC; }

double elapsed_max() const // return estimated maximum value for elapsed()
// Portability warning: elapsed_max() may return too high a value on systems
// where std::clock_t overflows or resets at surprising values.
{
return (double((std::numeric_limits<std::clock_t>::max)())
- double(_start_time)) / double(CLOCKS_PER_SEC);
}

double elapsed_min() const // return minimum value for elapsed()
{ return double(1)/double(CLOCKS_PER_SEC); }

private:
std::clock_t _start_time;
}; // timer

And std::clock() is defined in ctime.h in C++:

1
std::clock_t clock(void);

Where std::clock_t is also defined in ctime.h.

Defined in header
typedef /* unspecified */ clock_t;
Arithmetic type capable of representing the process running time of implementation-defined range and precision.

In fact, the above code calling timer is equivalent to:

1
2
3
4
5
6
7
8
9
10
11
#include <iosteram>
#include <ctime.h>
using namespace std;

int main(void){
clock_t start=clock();
// elapsed_max and elapsed_min are calculated similarly
// elapsed
clock_t end=clock()-start/CLOCKS_PER_SEC;
return 0;
}

Note: The number of clock ticks per second is defined by the macro CLOCKS_PER_SEC, which varies across different operating systems. On Win32, it’s 1,000 (with a timing precision of 1s/1,000=1ms), while on Linux, it’s 1,000,000 (with a timing precision of 1s/1,000,000=1μs).

progress_timer

progress_timer inherits from the timer class, thus having all member functions of the timer class (the interface is the same as timer). We can perform any operation on a progress_timer object that can be done on a timer object.

The constructor of progress_timer consists of the constructor of timer + the constructor defined in progress_timer. When constructing progress_timer, we need to pass an IO stream object to output the time to that stream upon destruction. The default is std::cout, but other standard output streams (ofstream/ostringstream) can be used alternatively, or the output of cout can be redirected using cout.rdbuf().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public:
explicit progress_timer( std::ostream & os = std::cout )
// os is hint; implementation may ignore, particularly in embedded systems
: timer(), noncopyable(), m_os(os) {}
~progress_timer()
{
// A) Throwing an exception from a destructor is a Bad Thing.
// B) The progress_timer destructor does output which may throw.
// C) A progress_timer is usually not critical to the application.
// Therefore, wrap the I/O in a try block, catch and ignore all exceptions.
try
{
// use istream instead of ios_base to workaround GNU problem (Greg Chicares)
std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed,
std::istream::floatfield );
std::streamsize old_prec = m_os.precision( 2 );
m_os << elapsed() << " s\n" // "s" is System International d'Unites std
<< std::endl;
m_os.flags( old_flags );
m_os.precision( old_prec );
}
catch (...) {} // eat any exceptions
} // ~progress_timer
private:
std::ostream & m_os;

As can be seen, when we construct a progress_timer, the timing starts automatically (timer::timer()), and when the progress_timer is destructed, it outputs the time elapsed from construction to destruction.

progress_display

progress_display can show the execution progress of the program in the console, but I think this class is pretty useless, so I won’t elaborate…

date_time

Boost has a date_time library to handle time, and date_time needs to be compiled to use, requiring linking to the boost_date_time library during compilation. The date_time consists of two parts: gregorian for handling dates and posix_time for handling time.

More about the interfaces of date_time in Boost can be found here: Chapter 10. Boost.Date_Time

date_time basically covers our needs for calculating between dates, but the date in the date_time library is based on the Gregorian calendar, supporting only dates from 1400-01-01 to 9999-12-31.

Without further ado, let’s look at some simple and common usages… More usages can be found in the Boost documentation or “The Complete Development of the Boost Library”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>

int main(int argc,char* argv[])
{
boost::gregorian::date testDate(2016,10,19);

// Check if this is a valid date
if(!testDate.is_not_a_date())
{
std::cout<<"yes"<<std::endl;
}else{
std::cout<<"error"<<std::endl;
}
// Accessing the date
std::cout<<testDate.year()<<"-"<<testDate.month()<<"-"<<testDate.day()<<std::endl;
std::cout<<testDate<<std::endl;
// Calculate the interval between two dates
boost::gregorian::date init(1994,11,11);
boost::gregorian::date now(2016,10,19);
std::cout<<now-init<<std::endl;

// Date calculations
// boost::gregorian::date test(2016,10,19);
// years()/months()/days() are defined in boost::gregorian namespace
// tomorrow
boost::gregorian::date tomorrow=now+boost::gregorian::days(1);
std::cout<<tomorrow<<std::endl;
// next month
boost::gregorian::date nextMonth=now+boost::gregorian::months(1);
std::cout<<nextMonth<<std::endl;
// next year
boost::gregorian::date nextYear=now+boost::gregorian::years(1);
std::cout<<nextYear<<std::endl;

return 0;
}

Some section code of the date class in date_time:

For more details, see boostcode/date_time/date.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
template<class T, class calendar, class duration_type_>
class date : private
boost::less_than_comparable<T
, boost::equality_comparable<T
> >
{
private:
typedef T date_type;
typedef calendar calendar_type;
typedef typename calendar::year_type year_type;
typedef typename calendar::month_type month_type;
typedef typename calendar::day_type day_type;
typedef typename calendar::ymd_type ymd_type;
public:
// Constructor
date(year_type y, month_type m, day_type d)
: days_(calendar::day_number(ymd_type(y, m, d)))
{}
date(const ymd_type& ymd)
: days_(calendar::day_number(ymd))
{}

// Member functions
year_type year() const
{
ymd_type ymd = calendar::from_day_number(days_);
return ymd.year;
}
month_type month() const
{
ymd_type ymd = calendar::from_day_number(days_);
return ymd.month;
}
day_type day() const
{
ymd_type ymd = calendar::from_day_number(days_);
return ymd.day;
}
bool is_not_a_date() const
{
return traits_type::is_not_a_number(days_);
}

// Operator overloading
date_type operator-=(const duration_type& dd)
{
*this = *this - dd;
return date_type(days_);
}
date_rep_type day_count() const
{
return days_;
}
// allow internal access from operators
date_type operator+(const duration_type& dd) const
{
if(dd.is_special())
{
return date_type(date_rep_type(days_) + dd.get_rep());
}
return date_type(date_rep_type(days_) + static_cast<date_int_type>(dd.days()));
}
date_type operator+=(const duration_type& dd)
{
*this = *this + dd;
return date_type(days_);
}

};

Smart Pointer

The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:Boost源码分析笔记
Author:LIPENGZHA
Publish Date:2016/10/19 21:39
World Count:2.9k Words
Link:https://en.imzlp.com/posts/18194/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!