您的位置:首页 > 其它

关于std::stringsteam的clear与str方法

2009-02-17 11:03 465 查看
最近在开发中需要用stringstream来进行时间的转换,结果遇到了一些麻烦,
啥也别说,请各位看段代码先。(翠花,上代码!)
#include <stdio.h>

#include <iostream>
#include <sstream>
using namespace std;

#include "boost/date_time/posix_time/posix_time.hpp"
using namespace boost::gregorian;
using namespace boost::posix_time;

#include <boost/thread/tss.hpp>
using namespace boost;

class CDateParser
{
public:
static time_t parseDate(const
string& s);
private:
static thread_specific_ptr<stringstream> m_ptr;
};

thread_specific_ptr<stringstream>
CDateParser::m_ptr;

/**
* @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使用情况也相当)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: