介绍
我正在编写一些通信应用程序。在 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
总是包含我的应用程序类的完整数据。在这种情况下,移动构造是有效的。
Getter
我认为将返回类型设置为 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
}
}
std::string_view
缺少所有修改器方法std::string
具有(当使用const引用时您不需要关心),同样缺少std::string::c_str()
方法。 - YSC