std::string vs const std::string& vs std::string_viewЗахват аргументовC++: std::vector.push_back() и классыКонвертация std::string в std::wstringИспользование std::string в dllВключение шаблонов и std::enable_ifИспользование std::move в списках инициализацииКак передать аргумент в std::thread по ссылке?Специализация шаблонной функции для std::stringC++,оптимизация подобия функции strstr(const char*,const char*)Запись текста в std::string дважды. С++Отличие между const string &s и string &s

std::string vs const std::string& vs std::string_view


Захват аргументовC++: std::vector.push_back() и классыКонвертация std::string в std::wstringИспользование std::string в dllВключение шаблонов и std::enable_ifИспользование std::move в списках инициализацииКак передать аргумент в std::thread по ссылке?Специализация шаблонной функции для std::stringC++,оптимизация подобия функции strstr(const char*,const char*)Запись текста в std::string дважды. С++Отличие между const string &s и string &s













2















Что правильнее передавать как аргумент функции(например в конструктор), если там эта строка будет просто скопирована?










поделиться|улучшить этот вопрос


























    2















    Что правильнее передавать как аргумент функции(например в конструктор), если там эта строка будет просто скопирована?










    поделиться|улучшить этот вопрос
























      2












      2








      2


      1






      Что правильнее передавать как аргумент функции(например в конструктор), если там эта строка будет просто скопирована?










      поделиться|улучшить этот вопрос














      Что правильнее передавать как аргумент функции(например в конструктор), если там эта строка будет просто скопирована?







      c++






      поделиться|улучшить этот вопрос













      поделиться|улучшить этот вопрос











      поделиться|улучшить этот вопрос




      поделиться|улучшить этот вопрос










      задан 9 часов назад









      tim barstim bars

      607




      607




















          3 ответа
          3






          текущие

          по дате публикации

          голоса


















          1














          Использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий. И это относится не только к std::string и std::string_view



          Для начала определимся с реализацией наших сущностей. Пусть std::string построен на трех указателях по 4 байта каждый (или указатель и два размера):



          class string

          //...
          pointer * m_begin; //Начало строки
          pointer * m_end; //Указатель за последний элемент
          pointer * m_end_of_storage; //Указатель за конец выделенной памяти
          ;


          std::string_view при этом реализован с помощью двух указателей (или указатель и размер):



          class string_view

          //...
          pointer m_data; //Указатель на начало данных
          pointer m_end; //Указатель за конец данных
          ;


          Упрощенно рассмотрим три версии простого кода:



          void other(std::string); //<-- функция, в которую всегда передается копия.

          void run(string_view v) //<-- Функция, которая вызывает функцию other

          //т.е. эта функция делает ту самую копию объекта
          other(v);


          void general(string str)

          //А из этой функции в функцию run передается строка
          other(str);



          Что будет сгенерировано компилятором и как рассматривать не будем, т.к. это сильно зависит от компилятора и параметров компиляции, но постараемся посмотреть что может быть и как.



          В нашем случае other передает копию string_view, т.е. general копирует два указателя (не говорим о возможности вызова конструктора копирования, подразумевая, что он самый тривиальный и в результирующем коде приведет просто к копированию двух членов класса). Затем строка копируется из string_view. Ничего сложного.



          Теперь возьмем тот же код, но при этом run будет принимать ссылку на string.



          void run(string const & v)

          other(v);


          void general(string str)

          other(str);
          //str используется, её нельзя перемещать в other



          Да, Вы правы, передача ссылки в функцию run - быстрая операция, можно считать, что это копирование указателя. Но у передачи ссылки есть и минусы. Один из них - функция run обращается к строке через ссылку, т.е. появляется дополнительный уровень косвенности, который может вылиться в большие затраты, чем "лишнее" копирование указателя в версии функции, принимающей string_view.



          Теперь рассмотрим третий вариант функции run:



          void run(string v)

          other(std::move(v));



          В данном случае копирование строки происходит еще в функции general (причем мы не перемещаем параметр str, т.к. он где-то там еще нужен далее). Затем функция run перемещает объект v в параметр функции other, а это в нашем случае приводит к копированию трех указателей и занулению старых. Очевидно, что в этом случае операций намного больше, чем со string_view, и, вполне вероятно, что косвенное обращение будет тоже быстрее. То есть это может быть самым тормознутым вариантом.



          А теперь представим, такую ситуацию:



          void run(string const &); //<-- имеется такая run
          void run(string_view); //или такая, нам без разницы

          class SomeClass

          string m_text;
          mutex m_mutex;
          void SomeClass::call()

          //Мы знаем, что run делает копию строки,
          //и запускает поток для её обработки
          lock_quard<mutex> locker;//объект у нас защищен мьютексом
          run(m_text);//Где-то там строка копируется и запускается новый поток
          //мы не знаем точный момент, когда строка скопируется,
          //поэтому вынуждены ждать выполнения run под защитой мьютекса,
          //т.к. в other содержаться указатели на защищенные члены нашего класса.
          //Вполне вероятно, что в этот момент другие
          //потоки уже хотят работать с нашим объектом,
          //но не могут, т.к. мьютекс захвачен.

          ;


          Я в комментариях описал проблему. А теперь возьмем ситуацию с копированием и перемещением:



          void run(string); //<-- теперь run принимает копию

          class SomeClass

          //..
          void SomeClass::call()

          //Мы знаем, что run принимает копию строки
          //и запускает поток для её обработки
          unique_lock<mutex> locker;//объект у нас защищен мьютексом
          string text_copy = m_text;//Под защитой выполняем копирование строки
          locker.unlock();//И разблокируем мьютекс, т.к.
          run(std::move(text_copy));//нам уже без разницы что-том делает run,
          //копия данных для него уже создана и другим потокам можно дать доступ к объекту

          ;


          У string_view при этом тоже имеются свои прелести. string_view в принципе не привязан к string - это просто данные и их размер. Т.е. string_view может работать не только с string:



          void run(string_view v);

          void general(string str)

          other(str);//ok


          void general(char const * str, size_t len)

          other(string_view(str, len));//ok


          void general(char const * str)

          other(string_view(str));//ok


          void general(std::vector<char> const & v)

          other(string_view(v.data(), v.size()));//ok



          В случае передачи ссылки придется сделать лишнюю копию строки, в случае передачи копии строки это не страшно, т.к. копия будет перемещена, но это всё равно может быть дороже. Однако, копия строки с перемещением может быть дешевле string_view, если, например для создания string_view потребуется сначала создать строку или какой-то другой буфер с данными. В таком случае будет лучше создать строку и переместить её.



          Но оптимизации также могут перевернуть всё с ног на голову. Когда нужно сделать копию строки, кажется, что это приведет к аллокации памяти и всё это будет медленно. В общем случае это верно, но есть такая штука, как SSO (small string optimization), которая позволяет хранить маленькие строки прямо в объекте string, используя сам объект как буфер для строки. В случае применения такой оптимизации копирование может оказаться равноценно или даже дешевле перемещения.



          То есть создав копию в вызывающей функции и переместив строку в вызываемую функцию, Вы если и потеряете скорость, то очень немного. Но это всё относится к ситуации, когда нужна копия на вызываемой стороне. Если же копия не нужна, то вариантов также масса.




          а для чего тогда стоит использовать string_view?




          string_view нужен как раз тогда, когда копия строки не нужна, но нужно сослаться на какое-то место и с ним работать как со строкой. Ранее нужно было либо писать свою "обертку" подобную string_view, либо копировать нужные данные из исходной строки и работать с ними.



          Всё сказанное выше весьма условно и служит только для демонстрации различных ситуаций.



          Как видите, применение того или иного средства полностью зависит от конкретных условий использования, применяемых алгоритмов, оптимизаций компилятора, устройства библиотеки, платформы на которой всё это работает и т.д., поэтому закончу тем, с чего начал - использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий.






          поделиться|улучшить этот ответ
































            2














            Просто std::string. А потом вместо компирования - перемещать через std::move.






            поделиться|улучшить этот ответ























            • а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

              – tim bars
              9 часов назад












            • это всё весьма и весьма сомнительно.

              – Croessmah
              9 часов назад











            • @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

              – HolyBlackCat
              8 часов назад












            • @Croessmah Расска́жите подробнее?

              – HolyBlackCat
              8 часов назад


















            1















            1. Если строка будет "просто скопирована", то вам следует реализовывать либо "ленивый" вариант семантики перемещения (передавать std::string по значению и затем делать из него перемещение), либо "полный" вариант семантики перемещения (писать две перегруженных функции: для const std::string & и для std::string &&), либо, возможно, реализовать forwarding (писать шаблонную функцию, принимающую универсальную сслыку и делающую std::forward в вашу копию).



              См. https://ru.stackoverflow.com/a/822789/182825



            2. std::string_view уместен везде, где вы будете просто анализировать строку, т.е. он является заменителем const std:string & в ситуациях, когда копирование не будет делаться.






            поделиться|улучшить этот ответ






















              Ваш ответ






              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "609"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "на платформе u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "Пользовательский контент попадает под действие u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003eлицензии cc by-sa 3.0u003c/au003e с u003ca href="https://stackoverflow.com/legal/content-policy"u003eуказанием ссылки на источникu003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













              черновик сохранён

              черновик удалён


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fru.stackoverflow.com%2fquestions%2f954084%2fstdstring-vs-const-stdstring-vs-stdstring-view%23new-answer', 'question_page');

              );

              Отправить без регистрации















              Необходима, но никому не показывается

























              3 ответа
              3






              текущие

              по дате публикации

              голоса








              3 ответа
              3






              текущие

              по дате публикации

              голоса









              текущие

              по дате публикации

              голоса






              текущие

              по дате публикации

              голоса









              1














              Использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий. И это относится не только к std::string и std::string_view



              Для начала определимся с реализацией наших сущностей. Пусть std::string построен на трех указателях по 4 байта каждый (или указатель и два размера):



              class string

              //...
              pointer * m_begin; //Начало строки
              pointer * m_end; //Указатель за последний элемент
              pointer * m_end_of_storage; //Указатель за конец выделенной памяти
              ;


              std::string_view при этом реализован с помощью двух указателей (или указатель и размер):



              class string_view

              //...
              pointer m_data; //Указатель на начало данных
              pointer m_end; //Указатель за конец данных
              ;


              Упрощенно рассмотрим три версии простого кода:



              void other(std::string); //<-- функция, в которую всегда передается копия.

              void run(string_view v) //<-- Функция, которая вызывает функцию other

              //т.е. эта функция делает ту самую копию объекта
              other(v);


              void general(string str)

              //А из этой функции в функцию run передается строка
              other(str);



              Что будет сгенерировано компилятором и как рассматривать не будем, т.к. это сильно зависит от компилятора и параметров компиляции, но постараемся посмотреть что может быть и как.



              В нашем случае other передает копию string_view, т.е. general копирует два указателя (не говорим о возможности вызова конструктора копирования, подразумевая, что он самый тривиальный и в результирующем коде приведет просто к копированию двух членов класса). Затем строка копируется из string_view. Ничего сложного.



              Теперь возьмем тот же код, но при этом run будет принимать ссылку на string.



              void run(string const & v)

              other(v);


              void general(string str)

              other(str);
              //str используется, её нельзя перемещать в other



              Да, Вы правы, передача ссылки в функцию run - быстрая операция, можно считать, что это копирование указателя. Но у передачи ссылки есть и минусы. Один из них - функция run обращается к строке через ссылку, т.е. появляется дополнительный уровень косвенности, который может вылиться в большие затраты, чем "лишнее" копирование указателя в версии функции, принимающей string_view.



              Теперь рассмотрим третий вариант функции run:



              void run(string v)

              other(std::move(v));



              В данном случае копирование строки происходит еще в функции general (причем мы не перемещаем параметр str, т.к. он где-то там еще нужен далее). Затем функция run перемещает объект v в параметр функции other, а это в нашем случае приводит к копированию трех указателей и занулению старых. Очевидно, что в этом случае операций намного больше, чем со string_view, и, вполне вероятно, что косвенное обращение будет тоже быстрее. То есть это может быть самым тормознутым вариантом.



              А теперь представим, такую ситуацию:



              void run(string const &); //<-- имеется такая run
              void run(string_view); //или такая, нам без разницы

              class SomeClass

              string m_text;
              mutex m_mutex;
              void SomeClass::call()

              //Мы знаем, что run делает копию строки,
              //и запускает поток для её обработки
              lock_quard<mutex> locker;//объект у нас защищен мьютексом
              run(m_text);//Где-то там строка копируется и запускается новый поток
              //мы не знаем точный момент, когда строка скопируется,
              //поэтому вынуждены ждать выполнения run под защитой мьютекса,
              //т.к. в other содержаться указатели на защищенные члены нашего класса.
              //Вполне вероятно, что в этот момент другие
              //потоки уже хотят работать с нашим объектом,
              //но не могут, т.к. мьютекс захвачен.

              ;


              Я в комментариях описал проблему. А теперь возьмем ситуацию с копированием и перемещением:



              void run(string); //<-- теперь run принимает копию

              class SomeClass

              //..
              void SomeClass::call()

              //Мы знаем, что run принимает копию строки
              //и запускает поток для её обработки
              unique_lock<mutex> locker;//объект у нас защищен мьютексом
              string text_copy = m_text;//Под защитой выполняем копирование строки
              locker.unlock();//И разблокируем мьютекс, т.к.
              run(std::move(text_copy));//нам уже без разницы что-том делает run,
              //копия данных для него уже создана и другим потокам можно дать доступ к объекту

              ;


              У string_view при этом тоже имеются свои прелести. string_view в принципе не привязан к string - это просто данные и их размер. Т.е. string_view может работать не только с string:



              void run(string_view v);

              void general(string str)

              other(str);//ok


              void general(char const * str, size_t len)

              other(string_view(str, len));//ok


              void general(char const * str)

              other(string_view(str));//ok


              void general(std::vector<char> const & v)

              other(string_view(v.data(), v.size()));//ok



              В случае передачи ссылки придется сделать лишнюю копию строки, в случае передачи копии строки это не страшно, т.к. копия будет перемещена, но это всё равно может быть дороже. Однако, копия строки с перемещением может быть дешевле string_view, если, например для создания string_view потребуется сначала создать строку или какой-то другой буфер с данными. В таком случае будет лучше создать строку и переместить её.



              Но оптимизации также могут перевернуть всё с ног на голову. Когда нужно сделать копию строки, кажется, что это приведет к аллокации памяти и всё это будет медленно. В общем случае это верно, но есть такая штука, как SSO (small string optimization), которая позволяет хранить маленькие строки прямо в объекте string, используя сам объект как буфер для строки. В случае применения такой оптимизации копирование может оказаться равноценно или даже дешевле перемещения.



              То есть создав копию в вызывающей функции и переместив строку в вызываемую функцию, Вы если и потеряете скорость, то очень немного. Но это всё относится к ситуации, когда нужна копия на вызываемой стороне. Если же копия не нужна, то вариантов также масса.




              а для чего тогда стоит использовать string_view?




              string_view нужен как раз тогда, когда копия строки не нужна, но нужно сослаться на какое-то место и с ним работать как со строкой. Ранее нужно было либо писать свою "обертку" подобную string_view, либо копировать нужные данные из исходной строки и работать с ними.



              Всё сказанное выше весьма условно и служит только для демонстрации различных ситуаций.



              Как видите, применение того или иного средства полностью зависит от конкретных условий использования, применяемых алгоритмов, оптимизаций компилятора, устройства библиотеки, платформы на которой всё это работает и т.д., поэтому закончу тем, с чего начал - использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий.






              поделиться|улучшить этот ответ





























                1














                Использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий. И это относится не только к std::string и std::string_view



                Для начала определимся с реализацией наших сущностей. Пусть std::string построен на трех указателях по 4 байта каждый (или указатель и два размера):



                class string

                //...
                pointer * m_begin; //Начало строки
                pointer * m_end; //Указатель за последний элемент
                pointer * m_end_of_storage; //Указатель за конец выделенной памяти
                ;


                std::string_view при этом реализован с помощью двух указателей (или указатель и размер):



                class string_view

                //...
                pointer m_data; //Указатель на начало данных
                pointer m_end; //Указатель за конец данных
                ;


                Упрощенно рассмотрим три версии простого кода:



                void other(std::string); //<-- функция, в которую всегда передается копия.

                void run(string_view v) //<-- Функция, которая вызывает функцию other

                //т.е. эта функция делает ту самую копию объекта
                other(v);


                void general(string str)

                //А из этой функции в функцию run передается строка
                other(str);



                Что будет сгенерировано компилятором и как рассматривать не будем, т.к. это сильно зависит от компилятора и параметров компиляции, но постараемся посмотреть что может быть и как.



                В нашем случае other передает копию string_view, т.е. general копирует два указателя (не говорим о возможности вызова конструктора копирования, подразумевая, что он самый тривиальный и в результирующем коде приведет просто к копированию двух членов класса). Затем строка копируется из string_view. Ничего сложного.



                Теперь возьмем тот же код, но при этом run будет принимать ссылку на string.



                void run(string const & v)

                other(v);


                void general(string str)

                other(str);
                //str используется, её нельзя перемещать в other



                Да, Вы правы, передача ссылки в функцию run - быстрая операция, можно считать, что это копирование указателя. Но у передачи ссылки есть и минусы. Один из них - функция run обращается к строке через ссылку, т.е. появляется дополнительный уровень косвенности, который может вылиться в большие затраты, чем "лишнее" копирование указателя в версии функции, принимающей string_view.



                Теперь рассмотрим третий вариант функции run:



                void run(string v)

                other(std::move(v));



                В данном случае копирование строки происходит еще в функции general (причем мы не перемещаем параметр str, т.к. он где-то там еще нужен далее). Затем функция run перемещает объект v в параметр функции other, а это в нашем случае приводит к копированию трех указателей и занулению старых. Очевидно, что в этом случае операций намного больше, чем со string_view, и, вполне вероятно, что косвенное обращение будет тоже быстрее. То есть это может быть самым тормознутым вариантом.



                А теперь представим, такую ситуацию:



                void run(string const &); //<-- имеется такая run
                void run(string_view); //или такая, нам без разницы

                class SomeClass

                string m_text;
                mutex m_mutex;
                void SomeClass::call()

                //Мы знаем, что run делает копию строки,
                //и запускает поток для её обработки
                lock_quard<mutex> locker;//объект у нас защищен мьютексом
                run(m_text);//Где-то там строка копируется и запускается новый поток
                //мы не знаем точный момент, когда строка скопируется,
                //поэтому вынуждены ждать выполнения run под защитой мьютекса,
                //т.к. в other содержаться указатели на защищенные члены нашего класса.
                //Вполне вероятно, что в этот момент другие
                //потоки уже хотят работать с нашим объектом,
                //но не могут, т.к. мьютекс захвачен.

                ;


                Я в комментариях описал проблему. А теперь возьмем ситуацию с копированием и перемещением:



                void run(string); //<-- теперь run принимает копию

                class SomeClass

                //..
                void SomeClass::call()

                //Мы знаем, что run принимает копию строки
                //и запускает поток для её обработки
                unique_lock<mutex> locker;//объект у нас защищен мьютексом
                string text_copy = m_text;//Под защитой выполняем копирование строки
                locker.unlock();//И разблокируем мьютекс, т.к.
                run(std::move(text_copy));//нам уже без разницы что-том делает run,
                //копия данных для него уже создана и другим потокам можно дать доступ к объекту

                ;


                У string_view при этом тоже имеются свои прелести. string_view в принципе не привязан к string - это просто данные и их размер. Т.е. string_view может работать не только с string:



                void run(string_view v);

                void general(string str)

                other(str);//ok


                void general(char const * str, size_t len)

                other(string_view(str, len));//ok


                void general(char const * str)

                other(string_view(str));//ok


                void general(std::vector<char> const & v)

                other(string_view(v.data(), v.size()));//ok



                В случае передачи ссылки придется сделать лишнюю копию строки, в случае передачи копии строки это не страшно, т.к. копия будет перемещена, но это всё равно может быть дороже. Однако, копия строки с перемещением может быть дешевле string_view, если, например для создания string_view потребуется сначала создать строку или какой-то другой буфер с данными. В таком случае будет лучше создать строку и переместить её.



                Но оптимизации также могут перевернуть всё с ног на голову. Когда нужно сделать копию строки, кажется, что это приведет к аллокации памяти и всё это будет медленно. В общем случае это верно, но есть такая штука, как SSO (small string optimization), которая позволяет хранить маленькие строки прямо в объекте string, используя сам объект как буфер для строки. В случае применения такой оптимизации копирование может оказаться равноценно или даже дешевле перемещения.



                То есть создав копию в вызывающей функции и переместив строку в вызываемую функцию, Вы если и потеряете скорость, то очень немного. Но это всё относится к ситуации, когда нужна копия на вызываемой стороне. Если же копия не нужна, то вариантов также масса.




                а для чего тогда стоит использовать string_view?




                string_view нужен как раз тогда, когда копия строки не нужна, но нужно сослаться на какое-то место и с ним работать как со строкой. Ранее нужно было либо писать свою "обертку" подобную string_view, либо копировать нужные данные из исходной строки и работать с ними.



                Всё сказанное выше весьма условно и служит только для демонстрации различных ситуаций.



                Как видите, применение того или иного средства полностью зависит от конкретных условий использования, применяемых алгоритмов, оптимизаций компилятора, устройства библиотеки, платформы на которой всё это работает и т.д., поэтому закончу тем, с чего начал - использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий.






                поделиться|улучшить этот ответ



























                  1












                  1








                  1







                  Использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий. И это относится не только к std::string и std::string_view



                  Для начала определимся с реализацией наших сущностей. Пусть std::string построен на трех указателях по 4 байта каждый (или указатель и два размера):



                  class string

                  //...
                  pointer * m_begin; //Начало строки
                  pointer * m_end; //Указатель за последний элемент
                  pointer * m_end_of_storage; //Указатель за конец выделенной памяти
                  ;


                  std::string_view при этом реализован с помощью двух указателей (или указатель и размер):



                  class string_view

                  //...
                  pointer m_data; //Указатель на начало данных
                  pointer m_end; //Указатель за конец данных
                  ;


                  Упрощенно рассмотрим три версии простого кода:



                  void other(std::string); //<-- функция, в которую всегда передается копия.

                  void run(string_view v) //<-- Функция, которая вызывает функцию other

                  //т.е. эта функция делает ту самую копию объекта
                  other(v);


                  void general(string str)

                  //А из этой функции в функцию run передается строка
                  other(str);



                  Что будет сгенерировано компилятором и как рассматривать не будем, т.к. это сильно зависит от компилятора и параметров компиляции, но постараемся посмотреть что может быть и как.



                  В нашем случае other передает копию string_view, т.е. general копирует два указателя (не говорим о возможности вызова конструктора копирования, подразумевая, что он самый тривиальный и в результирующем коде приведет просто к копированию двух членов класса). Затем строка копируется из string_view. Ничего сложного.



                  Теперь возьмем тот же код, но при этом run будет принимать ссылку на string.



                  void run(string const & v)

                  other(v);


                  void general(string str)

                  other(str);
                  //str используется, её нельзя перемещать в other



                  Да, Вы правы, передача ссылки в функцию run - быстрая операция, можно считать, что это копирование указателя. Но у передачи ссылки есть и минусы. Один из них - функция run обращается к строке через ссылку, т.е. появляется дополнительный уровень косвенности, который может вылиться в большие затраты, чем "лишнее" копирование указателя в версии функции, принимающей string_view.



                  Теперь рассмотрим третий вариант функции run:



                  void run(string v)

                  other(std::move(v));



                  В данном случае копирование строки происходит еще в функции general (причем мы не перемещаем параметр str, т.к. он где-то там еще нужен далее). Затем функция run перемещает объект v в параметр функции other, а это в нашем случае приводит к копированию трех указателей и занулению старых. Очевидно, что в этом случае операций намного больше, чем со string_view, и, вполне вероятно, что косвенное обращение будет тоже быстрее. То есть это может быть самым тормознутым вариантом.



                  А теперь представим, такую ситуацию:



                  void run(string const &); //<-- имеется такая run
                  void run(string_view); //или такая, нам без разницы

                  class SomeClass

                  string m_text;
                  mutex m_mutex;
                  void SomeClass::call()

                  //Мы знаем, что run делает копию строки,
                  //и запускает поток для её обработки
                  lock_quard<mutex> locker;//объект у нас защищен мьютексом
                  run(m_text);//Где-то там строка копируется и запускается новый поток
                  //мы не знаем точный момент, когда строка скопируется,
                  //поэтому вынуждены ждать выполнения run под защитой мьютекса,
                  //т.к. в other содержаться указатели на защищенные члены нашего класса.
                  //Вполне вероятно, что в этот момент другие
                  //потоки уже хотят работать с нашим объектом,
                  //но не могут, т.к. мьютекс захвачен.

                  ;


                  Я в комментариях описал проблему. А теперь возьмем ситуацию с копированием и перемещением:



                  void run(string); //<-- теперь run принимает копию

                  class SomeClass

                  //..
                  void SomeClass::call()

                  //Мы знаем, что run принимает копию строки
                  //и запускает поток для её обработки
                  unique_lock<mutex> locker;//объект у нас защищен мьютексом
                  string text_copy = m_text;//Под защитой выполняем копирование строки
                  locker.unlock();//И разблокируем мьютекс, т.к.
                  run(std::move(text_copy));//нам уже без разницы что-том делает run,
                  //копия данных для него уже создана и другим потокам можно дать доступ к объекту

                  ;


                  У string_view при этом тоже имеются свои прелести. string_view в принципе не привязан к string - это просто данные и их размер. Т.е. string_view может работать не только с string:



                  void run(string_view v);

                  void general(string str)

                  other(str);//ok


                  void general(char const * str, size_t len)

                  other(string_view(str, len));//ok


                  void general(char const * str)

                  other(string_view(str));//ok


                  void general(std::vector<char> const & v)

                  other(string_view(v.data(), v.size()));//ok



                  В случае передачи ссылки придется сделать лишнюю копию строки, в случае передачи копии строки это не страшно, т.к. копия будет перемещена, но это всё равно может быть дороже. Однако, копия строки с перемещением может быть дешевле string_view, если, например для создания string_view потребуется сначала создать строку или какой-то другой буфер с данными. В таком случае будет лучше создать строку и переместить её.



                  Но оптимизации также могут перевернуть всё с ног на голову. Когда нужно сделать копию строки, кажется, что это приведет к аллокации памяти и всё это будет медленно. В общем случае это верно, но есть такая штука, как SSO (small string optimization), которая позволяет хранить маленькие строки прямо в объекте string, используя сам объект как буфер для строки. В случае применения такой оптимизации копирование может оказаться равноценно или даже дешевле перемещения.



                  То есть создав копию в вызывающей функции и переместив строку в вызываемую функцию, Вы если и потеряете скорость, то очень немного. Но это всё относится к ситуации, когда нужна копия на вызываемой стороне. Если же копия не нужна, то вариантов также масса.




                  а для чего тогда стоит использовать string_view?




                  string_view нужен как раз тогда, когда копия строки не нужна, но нужно сослаться на какое-то место и с ним работать как со строкой. Ранее нужно было либо писать свою "обертку" подобную string_view, либо копировать нужные данные из исходной строки и работать с ними.



                  Всё сказанное выше весьма условно и служит только для демонстрации различных ситуаций.



                  Как видите, применение того или иного средства полностью зависит от конкретных условий использования, применяемых алгоритмов, оптимизаций компилятора, устройства библиотеки, платформы на которой всё это работает и т.д., поэтому закончу тем, с чего начал - использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий.






                  поделиться|улучшить этот ответ















                  Использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий. И это относится не только к std::string и std::string_view



                  Для начала определимся с реализацией наших сущностей. Пусть std::string построен на трех указателях по 4 байта каждый (или указатель и два размера):



                  class string

                  //...
                  pointer * m_begin; //Начало строки
                  pointer * m_end; //Указатель за последний элемент
                  pointer * m_end_of_storage; //Указатель за конец выделенной памяти
                  ;


                  std::string_view при этом реализован с помощью двух указателей (или указатель и размер):



                  class string_view

                  //...
                  pointer m_data; //Указатель на начало данных
                  pointer m_end; //Указатель за конец данных
                  ;


                  Упрощенно рассмотрим три версии простого кода:



                  void other(std::string); //<-- функция, в которую всегда передается копия.

                  void run(string_view v) //<-- Функция, которая вызывает функцию other

                  //т.е. эта функция делает ту самую копию объекта
                  other(v);


                  void general(string str)

                  //А из этой функции в функцию run передается строка
                  other(str);



                  Что будет сгенерировано компилятором и как рассматривать не будем, т.к. это сильно зависит от компилятора и параметров компиляции, но постараемся посмотреть что может быть и как.



                  В нашем случае other передает копию string_view, т.е. general копирует два указателя (не говорим о возможности вызова конструктора копирования, подразумевая, что он самый тривиальный и в результирующем коде приведет просто к копированию двух членов класса). Затем строка копируется из string_view. Ничего сложного.



                  Теперь возьмем тот же код, но при этом run будет принимать ссылку на string.



                  void run(string const & v)

                  other(v);


                  void general(string str)

                  other(str);
                  //str используется, её нельзя перемещать в other



                  Да, Вы правы, передача ссылки в функцию run - быстрая операция, можно считать, что это копирование указателя. Но у передачи ссылки есть и минусы. Один из них - функция run обращается к строке через ссылку, т.е. появляется дополнительный уровень косвенности, который может вылиться в большие затраты, чем "лишнее" копирование указателя в версии функции, принимающей string_view.



                  Теперь рассмотрим третий вариант функции run:



                  void run(string v)

                  other(std::move(v));



                  В данном случае копирование строки происходит еще в функции general (причем мы не перемещаем параметр str, т.к. он где-то там еще нужен далее). Затем функция run перемещает объект v в параметр функции other, а это в нашем случае приводит к копированию трех указателей и занулению старых. Очевидно, что в этом случае операций намного больше, чем со string_view, и, вполне вероятно, что косвенное обращение будет тоже быстрее. То есть это может быть самым тормознутым вариантом.



                  А теперь представим, такую ситуацию:



                  void run(string const &); //<-- имеется такая run
                  void run(string_view); //или такая, нам без разницы

                  class SomeClass

                  string m_text;
                  mutex m_mutex;
                  void SomeClass::call()

                  //Мы знаем, что run делает копию строки,
                  //и запускает поток для её обработки
                  lock_quard<mutex> locker;//объект у нас защищен мьютексом
                  run(m_text);//Где-то там строка копируется и запускается новый поток
                  //мы не знаем точный момент, когда строка скопируется,
                  //поэтому вынуждены ждать выполнения run под защитой мьютекса,
                  //т.к. в other содержаться указатели на защищенные члены нашего класса.
                  //Вполне вероятно, что в этот момент другие
                  //потоки уже хотят работать с нашим объектом,
                  //но не могут, т.к. мьютекс захвачен.

                  ;


                  Я в комментариях описал проблему. А теперь возьмем ситуацию с копированием и перемещением:



                  void run(string); //<-- теперь run принимает копию

                  class SomeClass

                  //..
                  void SomeClass::call()

                  //Мы знаем, что run принимает копию строки
                  //и запускает поток для её обработки
                  unique_lock<mutex> locker;//объект у нас защищен мьютексом
                  string text_copy = m_text;//Под защитой выполняем копирование строки
                  locker.unlock();//И разблокируем мьютекс, т.к.
                  run(std::move(text_copy));//нам уже без разницы что-том делает run,
                  //копия данных для него уже создана и другим потокам можно дать доступ к объекту

                  ;


                  У string_view при этом тоже имеются свои прелести. string_view в принципе не привязан к string - это просто данные и их размер. Т.е. string_view может работать не только с string:



                  void run(string_view v);

                  void general(string str)

                  other(str);//ok


                  void general(char const * str, size_t len)

                  other(string_view(str, len));//ok


                  void general(char const * str)

                  other(string_view(str));//ok


                  void general(std::vector<char> const & v)

                  other(string_view(v.data(), v.size()));//ok



                  В случае передачи ссылки придется сделать лишнюю копию строки, в случае передачи копии строки это не страшно, т.к. копия будет перемещена, но это всё равно может быть дороже. Однако, копия строки с перемещением может быть дешевле string_view, если, например для создания string_view потребуется сначала создать строку или какой-то другой буфер с данными. В таком случае будет лучше создать строку и переместить её.



                  Но оптимизации также могут перевернуть всё с ног на голову. Когда нужно сделать копию строки, кажется, что это приведет к аллокации памяти и всё это будет медленно. В общем случае это верно, но есть такая штука, как SSO (small string optimization), которая позволяет хранить маленькие строки прямо в объекте string, используя сам объект как буфер для строки. В случае применения такой оптимизации копирование может оказаться равноценно или даже дешевле перемещения.



                  То есть создав копию в вызывающей функции и переместив строку в вызываемую функцию, Вы если и потеряете скорость, то очень немного. Но это всё относится к ситуации, когда нужна копия на вызываемой стороне. Если же копия не нужна, то вариантов также масса.




                  а для чего тогда стоит использовать string_view?




                  string_view нужен как раз тогда, когда копия строки не нужна, но нужно сослаться на какое-то место и с ним работать как со строкой. Ранее нужно было либо писать свою "обертку" подобную string_view, либо копировать нужные данные из исходной строки и работать с ними.



                  Всё сказанное выше весьма условно и служит только для демонстрации различных ситуаций.



                  Как видите, применение того или иного средства полностью зависит от конкретных условий использования, применяемых алгоритмов, оптимизаций компилятора, устройства библиотеки, платформы на которой всё это работает и т.д., поэтому закончу тем, с чего начал - использование любого из альтернативных средств очень сильно зависит от ситуации, и выбирается исходя из конкретных условий.







                  поделиться|улучшить этот ответ














                  поделиться|улучшить этот ответ



                  поделиться|улучшить этот ответ








                  изменён 6 часов назад

























                  ответ дан 6 часов назад









                  CroessmahCroessmah

                  3,973717




                  3,973717























                      2














                      Просто std::string. А потом вместо компирования - перемещать через std::move.






                      поделиться|улучшить этот ответ























                      • а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                        – tim bars
                        9 часов назад












                      • это всё весьма и весьма сомнительно.

                        – Croessmah
                        9 часов назад











                      • @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                        – HolyBlackCat
                        8 часов назад












                      • @Croessmah Расска́жите подробнее?

                        – HolyBlackCat
                        8 часов назад















                      2














                      Просто std::string. А потом вместо компирования - перемещать через std::move.






                      поделиться|улучшить этот ответ























                      • а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                        – tim bars
                        9 часов назад












                      • это всё весьма и весьма сомнительно.

                        – Croessmah
                        9 часов назад











                      • @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                        – HolyBlackCat
                        8 часов назад












                      • @Croessmah Расска́жите подробнее?

                        – HolyBlackCat
                        8 часов назад













                      2












                      2








                      2







                      Просто std::string. А потом вместо компирования - перемещать через std::move.






                      поделиться|улучшить этот ответ













                      Просто std::string. А потом вместо компирования - перемещать через std::move.







                      поделиться|улучшить этот ответ












                      поделиться|улучшить этот ответ



                      поделиться|улучшить этот ответ










                      ответ дан 9 часов назад









                      HolyBlackCatHolyBlackCat

                      5,6041514




                      5,6041514












                      • а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                        – tim bars
                        9 часов назад












                      • это всё весьма и весьма сомнительно.

                        – Croessmah
                        9 часов назад











                      • @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                        – HolyBlackCat
                        8 часов назад












                      • @Croessmah Расска́жите подробнее?

                        – HolyBlackCat
                        8 часов назад

















                      • а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                        – tim bars
                        9 часов назад












                      • это всё весьма и весьма сомнительно.

                        – Croessmah
                        9 часов назад











                      • @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                        – HolyBlackCat
                        8 часов назад












                      • @Croessmah Расска́жите подробнее?

                        – HolyBlackCat
                        8 часов назад
















                      а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                      – tim bars
                      9 часов назад






                      а для чего тогда стоит использовать string_view? И чем это лучше чем константная ссылка, с ней то по идее будет вызван только copy конструктор

                      – tim bars
                      9 часов назад














                      это всё весьма и весьма сомнительно.

                      – Croessmah
                      9 часов назад





                      это всё весьма и весьма сомнительно.

                      – Croessmah
                      9 часов назад













                      @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                      – HolyBlackCat
                      8 часов назад






                      @timbars "чем это лучше" Тем, что при таком варианте мы можем в некоторых случаях избежать копирования - когда передаем в функцию временный объект (rvalue). string_view, имхо, нужен для функций, анализирующих строки или сегменты строк (при парсинге и т. п.). Как универсальный "параметр-строка" он не особо прижился, имхо, потому что часто требудется, чтобы параметр был null-terminated, чего string_view не дает.

                      – HolyBlackCat
                      8 часов назад














                      @Croessmah Расска́жите подробнее?

                      – HolyBlackCat
                      8 часов назад





                      @Croessmah Расска́жите подробнее?

                      – HolyBlackCat
                      8 часов назад











                      1















                      1. Если строка будет "просто скопирована", то вам следует реализовывать либо "ленивый" вариант семантики перемещения (передавать std::string по значению и затем делать из него перемещение), либо "полный" вариант семантики перемещения (писать две перегруженных функции: для const std::string & и для std::string &&), либо, возможно, реализовать forwarding (писать шаблонную функцию, принимающую универсальную сслыку и делающую std::forward в вашу копию).



                        См. https://ru.stackoverflow.com/a/822789/182825



                      2. std::string_view уместен везде, где вы будете просто анализировать строку, т.е. он является заменителем const std:string & в ситуациях, когда копирование не будет делаться.






                      поделиться|улучшить этот ответ



























                        1















                        1. Если строка будет "просто скопирована", то вам следует реализовывать либо "ленивый" вариант семантики перемещения (передавать std::string по значению и затем делать из него перемещение), либо "полный" вариант семантики перемещения (писать две перегруженных функции: для const std::string & и для std::string &&), либо, возможно, реализовать forwarding (писать шаблонную функцию, принимающую универсальную сслыку и делающую std::forward в вашу копию).



                          См. https://ru.stackoverflow.com/a/822789/182825



                        2. std::string_view уместен везде, где вы будете просто анализировать строку, т.е. он является заменителем const std:string & в ситуациях, когда копирование не будет делаться.






                        поделиться|улучшить этот ответ

























                          1












                          1








                          1








                          1. Если строка будет "просто скопирована", то вам следует реализовывать либо "ленивый" вариант семантики перемещения (передавать std::string по значению и затем делать из него перемещение), либо "полный" вариант семантики перемещения (писать две перегруженных функции: для const std::string & и для std::string &&), либо, возможно, реализовать forwarding (писать шаблонную функцию, принимающую универсальную сслыку и делающую std::forward в вашу копию).



                            См. https://ru.stackoverflow.com/a/822789/182825



                          2. std::string_view уместен везде, где вы будете просто анализировать строку, т.е. он является заменителем const std:string & в ситуациях, когда копирование не будет делаться.






                          поделиться|улучшить этот ответ














                          1. Если строка будет "просто скопирована", то вам следует реализовывать либо "ленивый" вариант семантики перемещения (передавать std::string по значению и затем делать из него перемещение), либо "полный" вариант семантики перемещения (писать две перегруженных функции: для const std::string & и для std::string &&), либо, возможно, реализовать forwarding (писать шаблонную функцию, принимающую универсальную сслыку и делающую std::forward в вашу копию).



                            См. https://ru.stackoverflow.com/a/822789/182825



                          2. std::string_view уместен везде, где вы будете просто анализировать строку, т.е. он является заменителем const std:string & в ситуациях, когда копирование не будет делаться.







                          поделиться|улучшить этот ответ












                          поделиться|улучшить этот ответ



                          поделиться|улучшить этот ответ










                          ответ дан 6 часов назад









                          AnTAnT

                          50.2k33895




                          50.2k33895



























                              черновик сохранён

                              черновик удалён
















































                              Спасибо за ваш ответ на Stack Overflow на русском!


                              • Пожалуйста, убедитесь, что публикуемое сообщение отвечает на поставленный вопрос. Предоставьте как можно больше деталей, расскажите про проведенное исследование!

                              Но избегайте


                              • Просьб помощи, уточнений или ответов на темы не относящиеся к вопросу.

                              • Ответов основанных на мнениях; приводите аргументы основанные только на реальном опыте.

                              Также, обратите внимание на заметку в справочном центре о том, как писать ответы.




                              черновик сохранён


                              черновик удалён














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fru.stackoverflow.com%2fquestions%2f954084%2fstdstring-vs-const-stdstring-vs-stdstring-view%23new-answer', 'question_page');

                              );

                              Отправить без регистрации















                              Необходима, но никому не показывается





















































                              Необходима, но никому не показывается














                              Необходима, но никому не показывается












                              Необходима, но никому не показывается







                              Необходима, но никому не показывается

































                              Необходима, но никому не показывается














                              Необходима, но никому не показывается












                              Необходима, но никому не показывается







                              Необходима, но никому не показывается







                              Popular posts from this blog

                              Mobil Contents History Mobil brands Former Mobil brands Lukoil transaction Mobil UK Mobil Australia Mobil New Zealand Mobil Greece Mobil in Japan Mobil in Canada Mobil Egypt See also References External links Navigation menuwww.mobil.com"Mobil Corporation"the original"Our Houston campus""Business & Finance: Socony-Vacuum Corp.""Popular Mechanics""Lubrite Technologies""Exxon Mobil campus 'clearly happening'""Toledo Blade - Google News Archive Search""The Lion and the Moose - How 2 Executives Pulled off the Biggest Merger Ever""ExxonMobil Press Release""Lubricants""Archived copy"the original"Mobil 1™ and Mobil Super™ motor oil and synthetic motor oil - Mobil™ Motor Oils""Mobil Delvac""Mobil Industrial website""The State of Competition in Gasoline Marketing: The Effects of Refiner Operations at Retail""Mobil Travel Guide to become Forbes Travel Guide""Hotel Rankings: Forbes Merges with Mobil"the original"Jamieson oil industry history""Mobil news""Caltex pumps for control""Watchdog blocks Caltex bid""Exxon Mobil sells service station network""Mobil Oil New Zealand Limited is New Zealand's oldest oil company, with predecessor companies having first established a presence in the country in 1896""ExxonMobil subsidiaries have a business history in New Zealand stretching back more than 120 years. We are involved in petroleum refining and distribution and the marketing of fuels, lubricants and chemical products""Archived copy"the original"Exxon Mobil to Sell Its Japanese Arm for $3.9 Billion""Gas station merger will end Esso and Mobil's long run in Japan""Esso moves to affiliate itself with PC Optimum, no longer Aeroplan, in loyalty point switch""Mobil brand of gas stations to launch in Canada after deal for 213 Loblaws-owned locations""Mobil Nears Completion of Rebranding 200 Loblaw Gas Stations""Learn about ExxonMobil's operations in Egypt""Petrol and Diesel Service Stations in Egypt - Mobil"Official websiteExxon Mobil corporate websiteMobil Industrial official websiteeeeeeeeDA04275022275790-40000 0001 0860 5061n82045453134887257134887257

                              Frič See also Navigation menuinternal link

                              Identify plant with long narrow paired leaves and reddish stems Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?What is this plant with long sharp leaves? Is it a weed?What is this 3ft high, stalky plant, with mid sized narrow leaves?What is this young shrub with opposite ovate, crenate leaves and reddish stems?What is this plant with large broad serrated leaves?Identify this upright branching weed with long leaves and reddish stemsPlease help me identify this bulbous plant with long, broad leaves and white flowersWhat is this small annual with narrow gray/green leaves and rust colored daisy-type flowers?What is this chilli plant?Does anyone know what type of chilli plant this is?Help identify this plant