Progress_display
progress_display可以在控制台上显示程序的执行进度,如果程序执行很耗费时间,那么它能够提供一个友好的用户界面,不至于让用户在等待中失去耐心。
progress_display位于名字空间boost,为了使用progress_display组件,需要包含头文件<boost/progress.hpp>,即:
#include <boost/progress.hpp>
using namspace boost;
类摘要
progress_display是一个独立的类,与 timer库中的其他两个组件——timer 和progress_timer没有任何联系,它的类摘要如下:
class progress_display : noncopyable
{
public:
progress_display( unsigned long expected_count );
progress_display( unsigned long expected_count_,
std::ostream & os,
const std::string & s1 = "\n",
const std::string & s2 = "",
const std::string & s3 = "" );
void restart( unsigned long expected_count );
unsigned long operator+=( unsigned long increment );
unsigned long operator++();
unsigned long count() const;
unsigned long expected_count() const;
};
progress_display的构造函数接受一个long型的参数expected_count,表示用于进度显示的基数,是最常用的创建progress_display的方法。
另一种形式的构造函数除了基数和流输出对象外,还接受三个字符串参数,定义显示的三行首字符串。但这个构造函数有点小问题,流输出对象通常都应该是cout,把进度输出到文件或者其他用户看不到的地方似乎没有多大的意义。
在构造后progress_display对象会显示出一个类似图形化进度条的界面,用两行以字符的形式显示百分比进度,像这样:
重载的加法操作符operator+=和 operator++用来增加计数,并在第三行用字符*显示进度百分比 count() / expected_count。成员函数count()可以返回当前的计数,当计数到达基数expected_count时表示任务已经完成,进度为100%。
用法
假设我们要把一些存储在std::vector中的字符串以每个一行的形式写入到文本文件中,因为字符串数量很多,而且有的很大,因此可能操作会耗费很多时间。progress_display可以让程序有一个友好的人机界面,让用户知道程序的进度。
使用progress_display首先要调用它的构造函数,传入进度基数,如:
progress_display pd(v.size());
随后就可以使用它重载的加法操作符(++pd)来根据程序的运行情况增加计数,直到完成任务。
#include <iostream>
#include <vector>
using namespace std;
// disable pragma warning
#define BOOST_ALLOW_DEPRECATED_HEADERS
#include <boost/progress.hpp>
using namespace boost;
//
void case1()
{
vector<string> v(100); //一个字符串向量
ofstream fs("./test.txt"); //文件输出流
//声明一个progress_display对象,基数是v的大小
//progress_display pd(v.size(),cout ,"%%%", "+++", "???");
progress_display pd(v.size());
//开始迭代遍历向量 处理字符串 写入文件
for (auto& x : v) //for+auto循环
{
fs << x << endl; //更新进度显示
++pd;
}
}
//
void case2()
{
vector<string> v(100, "aaa");
v[10] = ""; v[23] = "";
ofstream fs("./test.txt");
progress_display pd(v.size());
for (auto pos = v.begin(); pos != v.end(); ++pos) //使用迭代器遍历容器
{
fs << *pos << endl;
++pd;
if (pos->empty())
{
cout << "null string # "
<< (pos - v.begin()) << endl;
}
}
}
//
int main()
{
case1();
case2();
}
当程序处理了75个字符串时,控制台的显示大概如下:
如果改用progress_display另一种形式的构造函数,如:
progress_display pd(v.size(),cout ,"%%%", "+++", "???");
那么显示就会变成这样:
这种输出形式颇有点“画蛇添足”的味道,建议读者最好不要这么用。
注意事项
progress_display可以用作基本的进度显示,但它有个固有的缺陷:无法把进度显示输出与程序的输出分离。
这是因为progress_display和所有c++程序一样,都向标准输出(cout)输出字符,如果使用progress_display的程序也有输出操作,那么progress_display的进度显示就会一片混乱。
仍然使用刚才的写入文本文件的例子,我们希望显示进度的同时还能报告空的字符串的行号,像这样:
如case2一样,似乎一切都很好,但实际的运行结果却是:
很显然,for循环中的输出打乱了progress_display的正常输出,而 progress_display对此毫不知情,仍然按部就班地显示着百分比进度。
这个显示混乱的问题很难解决,因为我们无法预知庞大的程序之中哪个地方会存在一个可能会干扰progress_display的输出。一个可能(但远非完美〉的办法是在每次显示进度时都调用restart()重新显示进度刻度,然后用operator+=来指定当前进度,而不是简单地调用operator++,例如:
pd.restart(v.size());
pd += (pos - v.begin() + 1);