【问题标题】:How to construct a std::string from a std::vector<char>?如何从 std::vector<char> 构造 std::string?
【发布时间】:2011-02-25 08:38:54
【问题描述】:

没有(显而易见的)首先构建一个 C 风格的字符串,然后使用它来创建一个 std::string,是否有更快/替代/“更好”的方法来从字符向量初始化字符串?

【问题讨论】:

  • 不复制也可以吗?换句话说,它与std::vector&lt;char&gt; v2(std::move(v)) 做同样的事情,但将std::string 作为新对象。

标签: c++


【解决方案1】:

嗯,最好的方法是使用下面的构造函数:

template<class InputIterator> string (InputIterator begin, InputIterator end);

这会导致类似:

std::vector<char> v;
std::string str(v.begin(), v.end());

【讨论】:

    【解决方案2】:

    我认为你可以做到

    std::string s( MyVector.begin(), MyVector.end() );
    

    其中 MyVector 是您的 std::vector。

    【讨论】:

    • 除了在 VS2013 中,它在运行时断言无效的迭代器,除非你设置 _ITERATOR_DEBUG_LEVEL=1(在这种情况下它似乎工作正常)。
    【解决方案3】:

    使用 C++11,您可以使用std::string(v.data()),或者,如果您的向量末尾不包含'\0',则使用std::string(v.data(), v.size())

    【讨论】:

    • 即使使用 C++98,我相信你也可以做到 std::string(&v[0])。当然,如果向量是空终止的。
    • @Jamie:顺便说一下,在 C++98 中,string(&amp;v[0], v.size()) 也应该可以工作,但只能在assert(not v.empty()); 之后,因为如果向量为空,v[0]v.front()会调用未定义的行为。除了不必使用地址运算符的语法简单性之外,这是 C++11 的 data() 函数的真正好处,它甚至适用于空向量。
    • 非常正确。不幸的是,在可预见的未来,我的项目一直停留在 Visual Studio 2008 上。首先检查向量长度是对的。
    • 如果向量不包含 '\0',std::string(v.data()) 可能会导致更长的字符串。所以不要使用这种方式。
    • @heLomaN:std::string(v.data(), v.size()) 有什么问题,答案中明确提到了这个确切原因?
    【解决方案4】:
    std::string s(v.begin(), v.end());
    

    其中 v 几乎是任何可迭代的东西。 (特别是 begin() 和 end() 必须返回 InputIterators。)

    【讨论】:

      【解决方案5】:

      我喜欢 Stefan 的回答(2013 年 9 月 11 日),但想让它更强大一点:

      如果向量以空终止符结尾,则不应使用 (v.begin(), v.end()):应使用 v.data()(或 &v[0] 用于 C+ 之前的那些) +17)。

      如果 v 没有空终止符,则应使用 (v.begin(), v.end())。

      如果你使用 begin() 和 end() 并且向量确实有一个终止零,你会得到一个字符串 "abc\0" 例如,它的长度为 4,但实际上应该只有 " abc”。

      【讨论】:

      • 关于空终止符的点非常好,我掉进了那个陷阱。
      • (v.begin(), v.end())(v.data()) 之间是否存在性能差异?后者会是O(n)吗?
      【解决方案6】:

      为了完整起见,另一种方式是std::string(&amp;v[0])(尽管您需要确保您的字符串以空值结尾,并且通常首选std::string(v.data())

      不同之处在于您可以使用前一种技术将向量传递给想要修改缓冲区的函数,而 .data() 则无法做到这一点。

      【讨论】:

      • 为什么不能使用data()修改缓冲区?在我看来,如果你在非常量向量上调用 data(),它会返回一个 T *(如果你的向量是 const,'v[0]` 无论如何都会返回一个T const &amp;)。跨度>
      • @AdamH.Peterson 这似乎是标准的疏忽。 Std::vector 的数据既有 const 也有 non-const 函数,而在当前标准中,std::string 只有一个 const 函数:en.cppreference.com/w/cpp/string/basic_string/data 注意 C++17 添加了 non-const 版本,所以这可能不会无限期地出现这种情况 - 但是,当前标准规定“修改通过数据访问的字符数组具有未定义的行为。”
      • 如果v 是一个字符串,那将是正确的,但是目标类型是一个字符串并且v 是一个向量。 (但很高兴看到 C++17 将赋予字符串与向量奇偶校验。)
      • @AdamH.Peterson 你当然是对的。不久前回答了这个问题,我认为整个问题都是关于字符串的,没有检查。
      【解决方案7】:
      vector<char> vec;
      //fill the vector;
      std::string s(vec.begin(), vec.end());
      

      【讨论】:

      • 能否在代码中添加一些解释?
      • C++11 字符串库模板如下 default (1) string();复制 (2) 字符串 (const string& str);子字符串 (3) 字符串 (const string& str, size_t pos, size_t len = npos);来自 c-string (4) 字符串 (const char* s);来自缓冲区 (5) 字符串 (const char* s, size_t n);填充 (6) 字符串 (size_t n, char c); range (7) template string (InputIterator first, InputIterator last);初始化列表 (8) 字符串 (initializer_list il);移动 (9) 字符串 (string&& str) noexcept;我们正在关注第 7 个模板。
      • 嗨@TechCat!在回答您的下一个问题之前,请阅读writing a good answer。享受您在 SO 的住宿!
      • 你能用描述编辑你的答案吗?
      • 不知道为什么这被否决了,这是一个完全可以接受的答案。
      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 2017-08-04
      • 2013-09-21
      • 2018-12-02
      • 2012-03-07
      • 2014-10-24
      • 1970-01-01
      相关资源
      最近更新 更多