什么时候应该使用std :: string / std :: string_view作为参数/返回类型

时间:2019-06-18 12:11:47

标签: c++ string c++17 string-view

简介

我正在编写一些通讯应用程序。在C ++ 17之前(没有Boost),我使用std::string及其常量引用为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
    }
}

正在运行的演示:https://wandbox.org/permlink/TW8w3je3q3D46cjk

2 个答案:

答案 0 :(得分:4)

std::string_view是一种获取std::string const成员函数而无需创建std :: string的方法,如果您有char*或想要引用字符串的子集。

将其视为 const引用。如果它引用的对象由于任何原因而消失,则说明您有问题。如果您的代码可以返回引用,则可以返回string_view。

示例:

#include <cstdio>
#include <string>
#include <vector>
#include <string.h>
#include <iostream>

int main()
{
    char* a = new char[10];
    strcpy(a,"Hello");
    std::string_view s(a);
    std::cout << s; // OK    
    delete[] a;
    std::cout << s;     // whops. UD. If it was std::string, no problem, it would have been a copy
}

More info

答案 1 :(得分:1)

在以下情况下不返回字符串视图:

  • 呼叫者需要一个以空值终止的字符串。处理C API时通常是这种情况。
  • 您不要将字符串本身存储在某个地方。在这种情况下,您确实将字符串存储在成员中。

请意识到,通过更改原始容量等原始字符串的操作以及原始字符串被销毁,字符串视图将变得无效。如果调用方需要的字符串的时间长于存储该字符串的对象的生命周期,则他们可以从视图复制到自己的存储中。