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

来源:互联网 发布:京东程序员待遇怎么样 编辑:程序博客网 时间:2024/06/16 02:25

最近在开发中需要用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(conststring& s);

private:

        static thread_specific_ptr<stringstream> m_ptr;

};

 

thread_specific_ptr<stringstream>CDateParser::m_ptr;

 

 

/**

 * @brief Convert modify time string to time_tfor easy internal handling

 * @param str Modify time string returned byHTTP 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);

        }

 

        ptimep;

        m_ptr->clear();

        // m_ptr->str("");

        *m_ptr<< str;

        *m_ptr>> p;

        if (m_ptr->fail()) {

               cout<< "do not understand: "<< str << endl;

               return 0;

        }

 

        tmt = to_tm(p);

        return mktime(&t);

}

 

int main() {

        stringstr;

        time_tt;

 

        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对象,同时又保证线程安全.

运行的结果与期望的大相径庭,竟然三个都是:donot 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状态会在第一次失败后一直保持。

 在解决这个问题的过程中分别向boostmaillistgoogleC++ group提交了两个帖子,寻求帮助,googlegroups的帖子的链接如下:

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) {

        ptimep;

        stringstreamss(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;

 

        tmt = to_tm(p);

        return mktime(&t);

}

 

就存在极大的性能差别。

在笔者的环境下,100000次调用,共享stringstream只需23秒,而每次重建stringstream及相关对象的处理则需要19分19秒,二者执行效率竟相差50倍。(注:两种情况下CPU均维持在50%左右,Memory使用情况也相当)

原创粉丝点击