大卫的思维空间

自由的国度,思维的空间......
随笔 - 68, 文章 - 3, 评论 - 126, 引用 - 12

导航

<2009年4月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

公告

大卫语:
我不是天生的王者,除了奋斗,我别无选择!
David's Motto:
Since I am not an inborn victor, I have no choice but strive!

留言簿(6)

随笔分类

随笔档案

文章分类

文章档案

相册

相关链接

搜索

最新评论

阅读排行榜

评论排行榜

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

最近在开发中需要用stringstream来进行时间的转换,结果遇到了一些麻烦,

啥也别说,翠花,上代码!

#include



#include

#include

using namespace std;



#include "boost/date_time/posix_time/posix_time.hpp"

using namespace boost::gregorian;

using namespace boost::posix_time;



#include

using namespace boost;



class CDateParser

{

public:

static time_t parseDate(const string& s);

private:

static thread_specific_ptr m_ptr;

};



thread_specific_ptr CDateParser::m_ptr;



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倍。

posted on 2009-02-17 10:57 大卫的思维空间 阅读(1881) 评论(1)  编辑 收藏

评论

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

看的头都有些晕了!
2009-04-28 14:08 | 域名主机
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]