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

最近在开发中需要用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;

}

 

其中用到了boostdate_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 maillistgoogle 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使用情况也相当)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值