我最近发现需要将std::string
解析为boost::posix_time::ptime
。如何完成这项任务的问题在这里得到了很好的回答:How to parse date/time from string?。
我知道它只需要几行代码(基本上是istringstream声明,locale / time_input_facet imbuance,以及提取到ptime),但是我想将这个功能包装在一个便利函数中并使其可用作C ++库我使用ptimes的各种程序。
如果可能的话,我想从我的设计中获得C ++专家的一些反馈,这样我就可以知道我是否做了任何明显错误的事情,或者是否有更好的方法。特别是,我不太熟悉locales和time_input_facets如何工作,所以我希望我没有内存泄漏或任何东西。
这是:
namespace mydt {
void imbueDTFormat(std::istringstream& iss, const std::string& format );
void parse(const std::string& input, const std::string& format, boost::posix_time::ptime& out ); // (1)
void parse(const std::string& input, std::istringstream& iss, boost::posix_time::ptime& out ); // (2)
void parse(std::istringstream& iss, boost::posix_time::ptime& out ); // (3)
void imbueDTFormat(std::istringstream& iss, const std::string& format ) {
iss.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet(format) )); // see <http://en.cppreference.com/w/cpp/locale/locale/locale>: "Overload 7 is typically called with its second argument, f, obtained directly from a new-expression: the locale is responsible for calling the matching delete from its own destructor."
} // end imbueDTFormat()
void parse(const std::string& input, const std::string& format, boost::posix_time::ptime& out ) { // (1)
static std::istringstream iss;
imbueDTFormat(iss, format );
parse(input, iss, out );
} // end parse()
void parse(const std::string& input, std::istringstream& iss, boost::posix_time::ptime& out ) { // (2)
// assumes iss has already been imbued with the desired time_input_facet
iss.str(input);
parse(iss, out );
} // end parse()
void parse(std::istringstream& iss, boost::posix_time::ptime& out ) { // (3)
// assumes iss has already been imbued with the desired time_input_facet AND has been initialized with the input str
iss >> out;
} // end parse()
} // end namespace mydt
我写的第一个函数是parse(1)。它提供了最简单的界面;只需传递输入字符串,格式字符串和ptime OUT var,即可完成解析。它使用静态istringstream来完成解析,因此不需要分配。但是当我在编写它之后查看函数时,我意识到如果你有一个你反复想要解析的格式,那么从它重复分配一个新的time_input_facet并用它来填充相同的istringstream是浪费的。 p>
所以我认为你可以通过让调用代码创建自己的(可能是静态的)istringstream,使格式化一次,然后重复使用istringstream进行解析来做得更好。因此我为此目的写了解析(2)。所以调用代码可以为每种格式设置一个专用函数,如下所示:
void parseServerDT(const std::string& input, boost::posix_time::ptime& out );
void parseHostDT(const std::string& input, boost::posix_time::ptime& out );
// in main, or some other code context
boost::posix_time::ptime serverDT; parseServerDT(getServerDTStr(), serverDT );
boost::posix_time::ptime hostDT; parseHostDT(getHostDTStr(), hostDT );
void parseServerDT(const std::string& input, boost::posix_time::ptime& out ) {
static bool first = true;
static std::istringstream iss;
if (first) {
first = false;
mydt::imbueDTFormat(iss, SERVERDT_FORMAT );
} // end if
mydt::parse(input, iss, out );
} // end parseServerDT()
void parseHostDT(const std::string& input, boost::posix_time::ptime& out ) {
static bool first = true;
static std::istringstream iss;
if (first) {
first = false;
mydt::imbueDTFormat(iss, HOSTDT_FORMAT );
} // end if
mydt::parse(input, iss, out );
} // end parseHostDT()
我认为这种设计应该为调用代码提供最大的便利,并且应该最小化内存和性能影响。您可以根据需要定义任意数量的parseXDT()函数(甚至可以创建一个宏来减少这些函数中的重复代码。)
任何反馈都会非常感激。谢谢!
答案 0 :(得分:1)
至少
制作静态threadlocal。由于缺乏编译器,这涉及动态分配它们(不是问题,因为它是一次性成本)
最重要的是,在重新使用之前清除流错误状态和内容
void parseHostDT(const std::string& input, boost::posix_time::ptime& out ) {
thread_local std::istringstream* iss = [] {
first = false;
mydt::imbueDTFormat(iss, HOSTDT_FORMAT);
}();
iss->clear();
iss->str("");
mydt::parse(input, iss, out);
}