关于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使用情况也相当)
啥也别说,请各位看段代码先。(翠花,上代码!)
#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使用情况也相当)
相关文章推荐
- 关于从std::vector中删除std::string的方法
- 关于cocos2dx ios 内支付 出现iOSProductByIdentifier(std::string &identifier) 为nullptr 的问题 解决方法
- Java StringBuilder 清空Clear方法
- 聊聊C++临时对象的析构时间点------顺便再次提醒大家谨慎使用string的c_str方法
- java中关于String的split(String regex, int limit) 方法
- 关于PB中的执行string 形式的SQL语句的方法
- std::string 转BSTR的方法
- 关于Python中,re.sub(pattern, repl, string, count=0, flags=0)方法的个人理解
- 作为局部变量的std::string和标准库容器一种内存优化方法
- java.lang.StringBuffer.append(char[] str)方法实例
- (转)清空std::stringstream,联系到stream的clear()和清空
- 关于std::fstream以及std::ifstream打开中文路径名失败的问题和解决方法
- Oracle LPAD(String str,int length,String addStr)函数 使用方法
- 几种C++ std::string和std::wstring相互转换的转换方法
- js中精确判断对象类型--关于typeof 和Object.prototype.toString方法的区别
- 几种C++ std::string和std::wstring相互转换的转换方法
- MFC中 将std::string转换为LPCTSTR的方法
- "std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const"
- 摘录的一篇文章-关于对string方法的扩展
- 关于java.sql.SQLException: Incorrect string value的解决方法