Когда я должен использовать std :: string / std :: string_view для параметра / возвращаемого типа - PullRequest
1 голос
/ 18 июня 2019

Введение

Я пишу какое-то коммуникационное приложение. До 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 ]

4 голосов
/ 18 июня 2019

std::string_view - это способ получения std::string константных функций-членов без создания std :: string, если у вас есть 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
}

Подробнее .

1 голос
/ 18 июня 2019

Не возвращать строковое представление, когда:

  • Вызывающей стороне нужна строка с нулевым символом в конце. Это часто имеет место при работе с C API.
  • Вы не храните саму строку где-нибудь. В этом случае вы сохраняете строку в элементе.

Имейте в виду, что представление строки становится недействительным в результате операций с исходной строкой, таких как изменение емкости, а также в случае уничтожения исходной строки. Если вызывающая сторона нуждается в строке дольше, чем время жизни объекта, в котором хранится строка, то они могут скопировать из представления в свое собственное хранилище.

...