【发布时间】:2019-06-18 12:11:47
【问题描述】:
简介
我正在编写一些通信应用程序。在 C++17(没有 Boost)之前,我使用 std::string 并将其 const 引用作为 cls1。
从 C++17 开始,我将 std::string_view 作为 cls2 引入我的代码。
但是,我没有明确的政策何时应该使用std::string_view。我的通信应用程序从网络接收数据并将其存储到recv_buffer。并从recv_buffer 创建一些应用程序类。
建筑
如果我只关注cls1 的构造函数,移动构造是有效的。但我认为参数s 来自哪里。如果它最初来自recv_buffer,我可以在接收(很早)点创建std::string_view。在启用recv_buffer 的生命周期期间,请在任何地方使用std::string_view。如果我需要存储recv_buffer 的部分然后创建std::string。
我注意到的唯一例外是recv_buffer 始终包含我的应用程序类的完整数据。在这种情况下,移动构造是有效的。
吸气剂
我认为将返回类型用作std::string_view 具有优势。一些成员函数如substr() 是有效的。但到目前为止,我没有看到任何缺点。
问题
我怀疑我可能只看到std::string_view 的优点。在重写很多代码之前,我想知道你的想法。
PoC 代码
#include <string>
struct cls1 {
explicit cls1(std::string s):s_(std::move(s)) {}
std::string const& get() const { return s_; }
private:
std::string s_;
};
struct cls2 {
explicit cls2(std::string_view s):s_(s) {}
std::string_view get() const { return s_; }
private:
std::string s_;
};
#include <iostream>
int main() {
// If all of the receive buffer is the target
{
std::string recv_buffer = "ABC";
cls1 c1(std::move(recv_buffer)); // move construct
std::cout << c1.get().substr(1, 2) << std::endl; // create new string
}
{
std::string recv_buffer = "ABC";
cls2 c2(recv_buffer); // copy happend
std::cout << c2.get().substr(1, 2) << std::endl; // doesn't create new string
}
// If a part of the receive buffer is the target
{
std::string recv_buffer = "<<<ABC>>>";
cls1 c1(recv_buffer.substr(3, 3)); // copy happend and move construct
std::cout << c1.get().substr(1, 2) << std::endl; // create new string
}
{
std::string recv_buffer = "<<<ABC>>>";
std::string_view ref = recv_buffer;
cls2 c2(ref.substr(3, 3)); // string create from the part of buffer directly
std::cout << c2.get().substr(1, 2) << std::endl; // doesn't create new string
}
}
【问题讨论】:
-
几天前有人问了非常相似的问题:stackoverflow.com/questions/56601261/…
-
考虑 string_view 作为参考。如果它所指的对象消失了,那你就有问题了。
-
另外,
std::string_view缺少std::string拥有的所有修饰符方法(在使用 const ref 时你不关心),std::string::c_str()也一样。
标签: c++ string c++17 string-view