【问题标题】:How to avoid repeated istringstream construction when converting stream of string tokens转换字符串标记流时如何避免重复的字符串流构造
【发布时间】:2016-08-02 23:48:15
【问题描述】:

我(打算)使用this answer 中的代码从 CSV 读取内容。本质上,我在连续的, 字符之间获得了一个字符串迭代器;但我不想将它们放在字符串向量中,而是想将这些字符串解析为(任意)类型 T 的元素,它来自模板参数。所以...

template <typename T>
void foo(const std::string& line) 
{
    // ....
    std::vector<T> vec;
    using namespace boost;
    tokenizer<escaped_list_separator<char> > tk(
       line, escaped_list_separator<char>('\\', ',', '\"'));
    for (tokenizer<escaped_list_separator<char> >::iterator i(tk.begin());
       i!=tk.end();++i) 
    {
       /* magic goes here */
    }

我可以使用 istringstream`(例如建议 here):

std::istringstream iss(*i);
T t; iss >> t;
vec.push_back(t);

但这太过分了(我可能在这里建造了两次甚至三次)。如果 C++ 有一个像 std::to_string 这样的 std::from_string(),那么我会这样做

vec.emplace_back(std::from_string(*i));

但这并不存在。也许boost::lexical_cast?我真的更喜欢使用标准的东西。

我应该怎么做?

【问题讨论】:

  • 创建类似from_string 函数的唯一“通用”方法 使用字符串流,这实际上是boost::lexical_cast 的工作原理。当然,它确实依赖于类型(T 不管是什么)有一个适当的 `operator>>` 重载。您可能对数字之类的东西有一些专长,例如strtodstoi 被使用)但除此之外,没有办法逃脱 istringstream 的魔掌。
  • 即使存在from_string 函数,我也看不到它在性能/空间方面有多大改善。仅 2-3n 个额外操作,导致总体 O(n)。简洁的代码,你可以封装你自己的模板from_stringsstreams。
  • @aybassiony: 1. 你的意思是 from_string。 2. istringstream 可能需要一些构造 3. istringstream 自己进行窥视、标记化、维护下一个未使用的位置等,而在我的情况下,我知道整个字符串中只有一个值。我确信这会带来一些性能优势。

标签: c++ c++11 tostring generic-programming lexical-cast


【解决方案1】:

制作字符串流static thread_local

T parse (const string& line){
  static thread_local istringstream stream;
  stream.str(""); //flush the stream
  //keep using stream
}

如果你的应用是单线程的,你可以放弃thread_local

不涉及将流保持为函数静态的其他解决方案是用Parser 对象包装流,并继续使用该对象,用str 刷新它的内部缓冲区

class Parser{
  std::stringstream stream;
  public:
  void parse(const std::string& data){
     stream.str("");
     // the rest
  }

}

Parser parser;
parser.parse("my,data");
parser.parse("other,data");

编辑: 为了防止每个T 类型的实例化,将流封装在不同的函数中, 创建一个辅助函数,在每个线程中构造一次std::istringstream

namespace detail {
istringstream& getStream(){
      static thread_local istringstream stream;
      stream.str("");
      return stream;
}
} // namespace detail

template<class T>
void parse(){
   auto& stream = detail::getStream();
   //do soemthing with stream

}

【讨论】:

  • 你的头像是 Dangerous Dave 吗?
  • 是的。我是戴夫。我很危险:)
  • 等一下,您的模板化解析函数将为 T 的每个值提供一个单独的 istream 对象。这不太好...如何保留静态 thread_local 变量的未模板化 istringstream getter 函数?另外,thread_local 是 C++11 吗? C++14? C++17?
  • 会的,但是您要使用多少种字符串类型? 2? 4?构建 4 个字符串流对象没什么。而 thread_local + 魔法静态是 C++14
  • 我的意思是,让我们假设你有四种类型的字符串(string、wstring、u16string、u32string)并且你从 10 个不同的线程中激活了这个函数。您将只构建 40 个对象,这将需要什么? 20纳秒?真的没什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
相关资源
最近更新 更多