/**
* @brief Convert modify time string to time_t for easy internal handling
* @param str Modify time string returned by HTTP server, e.g. "Fri, 18 Jul 2008 11:53:14 GMT"
* @return Corresponding time_t result
*/
time_t CDateParser::parseDate(const string& str)
{
if (m_ptr.get() == 0) {
stringstream* pss = new stringstream();
time_input_facet* timefacet = new time_input_facet("%a, %d %b %Y %H:%M:%S %z"); // will be automatically deleted by related locale object
pss->imbue(locale(pss->getloc(), timefacet));
m_ptr.reset(pss);
}
ptime p;
m_ptr->clear();
// m_ptr->str("");
*m_ptr << str;
*m_ptr >> p;
if (m_ptr->fail()) {
cout << "do not understand: " << str << endl;
return 0;
}
tm t = to_tm(p);
return mktime(&t);
}
int main() {
string str;
time_t t;
str = "1 GMT";
t = CDateParser::parseDate(str);
cout << ctime(&t) << endl;
str = "Fri, 18 Jul 2008 11:53:14 GMT";
t = CDateParser::parseDate(str);
cout << ctime(&t) << endl;
str = "Sat, 19 Jul 2008 11:53:14 GMT";
t = CDateParser::parseDate(str);
cout << ctime(&t) << endl;
}
其中用到了boost的date_time/thread(TSS),使用TSS主要是为了重用stringstream对象,同时又保证线程安全.
运行的结果与期望的大相径庭,竟然三个都是:do not understand.
为什么呢?答案就在clear,这个方法仅仅只重置了stringstream对象的状态标示,并不能清除其已有的内容;并且,stringstream还有很容易被忽视的问题:我们必须显式清空之前放入stringstream的内容,<<的内容不会在>>后就被扔掉了(确实也应该如此设计,不然的话basic_istream就不会有seekg这个方法了)。
下面的文章重点讨论了后面这个问题:
http://hi.baidu.com/xxai/blog/item/6d7bed038c0f52ef09fa934b.html
有了上面这些对于stringstream的认识之后,答案是很明显的,我们仅需要在clear后添加一行代码:
m_ptr->str("");
以清除stringstream先前的内容。
注意:clear是必须的,否则fail状态会在第一次失败后一直保持。
在解决这个问题的过程中分别向boost maillist和google C++ group提交了两个帖子,寻求帮助,google groups的帖子的链接如下:
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a334defcad5bbe9a#
虽然我在收到回复之前已经google出了答案,但是还是不得不佩服groups里的高人的严谨与热心,有兴趣的朋友可以去看看。
另:下面的链接包含了对stringstream的基本介绍:
http://www.cppblog.com/Sandywin/archive/2007/07/13/27984.html
最后补充两点:
1、static/global变量可以同时是TSS(TLS);
2、stringstream属于比较重量级的对象,如果需要频繁调用相关代码,则应考虑在多次调用间共享该对象。
如上面的parseDate实现与以下实现:
time_t CDateParser2::parseDate(const string& s) {
ptime p;
stringstream ss(s.c_str());
time_input_facet* timefacet = new time_input_facet("%a, %d %b %Y %H:%M:%S %z"); // will be automatically deleted by related locale object
ss.imbue(locale(locale::classic(), timefacet));
ss >> p;
tm t = to_tm(p);
return mktime(&t);
}
就存在极大的性能差别。
在笔者的环境下,100000次调用,共享stringstream只需23秒,而每次重建stringstream及相关对象的处理则需要19分19秒,二者执行效率竟相差50倍。(注:两种情况下CPU均维持在50%左右,Memory使用情况也相当)