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

Tak*_*ndo 5 c++ string string-view c++17

介绍

我正在编写一些通信应用程序。在 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. 在重新编写许多代码之前,我想知道您的想法。

验证码

#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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*kis 9

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

将其视为常量引用。如果它引用的对象由于任何原因消失(或更改),则说明您有问题。如果您的代码可以返回引用,则可以返回 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
}
Run Code Online (Sandbox Code Playgroud)

更多信息

编辑:它没有c_str()成员,因为这需要在子字符串的末尾创建一个 \0 ,这在没有修改的情况下无法完成。


eer*_*ika 6

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

  • 调用者需要一个以空字符结尾的字符串。处理 C API 时经常出现这种情况。
  • 您不会将字符串本身存储在某处。在这种情况下,您确实将字符串存储在成员中。

请注意,对原始字符串进行操作(例如更改容量)以及原始字符串被破坏时,字符串视图会变得无效。如果调用者需要该字符串的时间长于存储该字符串的对象的生命周期,那么他们可以从视图复制到自己的存储中。

  • @TakatoshiKondo 返回字符串视图或对本地字符串的引用都不好,是的。 (2认同)