Конкатенация std::string_view ?!
От: Videoman Россия https://hts.tv/
Дата: 30.05.23 09:48
Оценка:
Неожиданно для себя обнаружил неочевидное, для себя, поведение связки std::string и std::string_view. Из коробки к строке нельзя конкатенировать отображение строки.
#include <iostream>
#include <string>

/*
std::string operator+(const std::string& str, const std::string_view& view) 
{
    return str + std::string(view);
}
//*/

int main() 
{
    std::string str1 = "some string 1";
    std::string_view str2 = "some string 2";

    std::cout << str1 + str2;

    return 1;
}


Вопросы к знатокам:
— с чем связано такое решение в стандарте?
— чем такая конкатенация отличается от конкатенации с сырой С-шной строкой?
Re: Конкатенация std::string_view ?!
От: Chorkov Россия  
Дата: 30.05.23 11:02
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Неожиданно для себя обнаружил неочевидное, для себя, поведение связки std::string и std::string_view. Из коробки к строке нельзя конкатенировать отображение строки.

V>
V>Вопросы к знатокам:
V>- с чем связано такое решение в стандарте?
V>- чем такая конкатенация отличается от конкатенации с сырой С-шной строкой?

Догадка:
1) string_view не поддерживает никакие операции с аллокацией памяти.

2) Если такое сложение разрешить, велика вероятность сделать ошибку типа:
std::string_view result = "foo"s + "bar"sv;  //< store reference on temporary string

По этой же причине, нет неявного преобразования string_view->string.
Re[2]: Конкатенация std::string_view ?!
От: Videoman Россия https://hts.tv/
Дата: 30.05.23 12:53
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Догадка:

C>1) string_view не поддерживает никакие операции с аллокацией памяти.

Это понятно. Из-за этого же разрешено только явное преобразование к стоке.

C>2) Если такое сложение разрешить, велика вероятность сделать ошибку типа:

C>
C>std::string_view result = "foo"s + "bar"sv;  //< store reference on temporary string
C>

Это тоже понятно, также как и операция сложения двух нативных строк, тут ничего нового. А почему нельзя к строке прибавлять string_view, а нативную можно, строка же поддерживает переаллокацию?
Отредактировано 30.05.2023 12:54 Videoman . Предыдущая версия .
Re: Конкатенация std::string_view ?!
От: watchmaker  
Дата: 30.05.23 12:57
Оценка: 22 (3)
Здравствуйте, Videoman, Вы писали:

V>- с чем связано такое решение в стандарте?


Автор оригинального proposal хотел упороться по оптимизации и сделать конкатенацию через string builder, но не смог. Остался такой вот задаел на будущее, который никому в таком виде не нужен.

А потом всем было несколько лет лень написать proposal на исправление этой ситуации (потому что по формальным правилам это не дефект стандарта).

Ну и собственно вот, дождались: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2591r3.html


V>- чем такая конкатенация отличается от конкатенации с сырой С-шной строкой?



Если не считать обычного различия, что С-string не может содержать внутри символ \0, а string_view может, то различий особо нет. Причина отсутствия operator+(string, view) в c++17 не связана с этим.
Тем более, что там же уже был operator+=(string, view).




V> return str + std::string(view);


Как быстрая заплатка — ок. Но есть же в string методы append или operator+=, которые позволяют приписать что угодно к строке без конвертации view в строку, что сэкономит аллокацию под временную копию строки.
Re[2]: Конкатенация std::string_view ?!
От: Videoman Россия https://hts.tv/
Дата: 30.05.23 13:17
Оценка: -1
Здравствуйте, watchmaker, Вы писали:

W>Если не считать обычного различия, что С-string не может содержать внутри символ \0, а string_view может, то различий особо нет. Причина отсутствия operator+(string, view) в c++17 не связана с этим.

W>Тем более, что там же уже был operator+=(string, view).

Тут не понял. Где кто был уже? Я в С++17 сейчас, оператора такого нет

W>Как быстрая заплатка — ок. Но есть же в string методы append или operator+=, которые позволяют приписать что угодно к строке без конвертации view в строку, что сэкономит аллокацию под временную копию строки.


Я просто демонстрировал проблему по быстрому. Основная проблема у меня в том, что где-то по делу меняя string на string_view, код перестаёт работать на конкатенациях и теперь мне приходится его переписывать. У меня нет каких-то особых требований по быстрой работе со строками, это не критические места, которые вызываются не чаще исключений.
Re[3]: Конкатенация std::string_view ?!
От: B0FEE664  
Дата: 30.05.23 14:02
Оценка: 4 (1)
Здравствуйте, Videoman, Вы писали:

W>>Тем более, что там же уже был operator+=(string, view).

V>Тут не понял. Где кто был уже? Я в С++17 сейчас, оператора такого нет

В С++17 оператор str += sv есть, см. номер 5, а вот оператора str + sv нет.
#include <iostream>
#include <string>

int main() 
{
    std::string str1 = "some string 1";
    std::string_view str2 = "some string 2";

    std::cout << (std::string{str1} += str2);

    return 1;
}
И каждый день — без права на ошибку...
Re[4]: Конкатенация std::string_view ?!
От: Videoman Россия https://hts.tv/
Дата: 30.05.23 14:18
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В С++17 оператор str += sv есть, см. номер 5, а вот оператора str + sv нет.


Да, понятно, спасибо! Историю как "закалялся" string_view пропустил, поэтому мотивацию стандарта до конца не понял. А проблема началась неожиданно. Раньше некоторые старые функции использовали const string& в качестве типа аргумента и "новый" string_view туда не передать, без явного преобразования. Теперь вот string_view распространяется по коду как вирус .
Re[2]: Конкатенация std::string_view ?!
От: B0FEE664  
Дата: 30.05.23 14:33
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Автор оригинального proposal хотел упороться по оптимизации и сделать конкатенацию через string builder, но не смог. Остался такой вот задаел на будущее, который никому в таком виде не нужен.


Я не понял. Вот из за этого случая:
#define QT_USE_QSTRINGBUILDER
#include <QtCore/QString>
(...)
const auto path = "hello " +  QString::fromLatin1("world");
qDebug() << path; // CRASH

не будет string builder'а?
Грустно.
Это же разрешимая ситуация: достаточно при инициализации builder'а другим объектом builder'а делать полную копию всех подстрок в одну строку.
Или есть ещё какие-то сценарии?
И каждый день — без права на ошибку...
Re[5]: Конкатенация std::string_view ?!
От: B0FEE664  
Дата: 30.05.23 15:10
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Да, понятно, спасибо! Историю как "закалялся" string_view пропустил, поэтому мотивацию стандарта до конца не понял. А проблема началась неожиданно. Раньше некоторые старые функции использовали const string& в качестве типа аргумента и "новый" string_view туда не передать, без явного преобразования. Теперь вот string_view распространяется по коду как вирус .


Я историю string_view не знаю, но по коду видно, что с string_view всё несколько странно. Например, почему operator[] не noexcept?:

constexpr const_reference operator[]( size_type pos ) const;
...
Exceptions
Does not throw

отсюда
И каждый день — без права на ошибку...
Re[6]: Конкатенация std::string_view ?!
От: so5team https://stiffstream.com
Дата: 30.05.23 15:27
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Я историю string_view не знаю, но по коду видно, что с string_view всё несколько странно. Например, почему operator[] не noexcept?:

BFE>

BFE>constexpr const_reference operator[]( size_type pos ) const;


Там еще и вот такой конструктор не помечен как noexcept:
constexpr basic_string_view( const CharT* s, size_type count );

ЕМНИП, некоторые реализации могут бросать из этих методов исключения в отладочном режиме. Отсюда и отсутствие noexcept там, где как раз noexcept и ожидаешь
Re[6]: Конкатенация std::string_view ?!
От: andyp  
Дата: 30.05.23 16:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Я историю string_view не знаю, но по коду видно, что с string_view всё несколько странно. Например, почему operator[] не noexcept?:


По той же причине, почему и у std::vector он без noexcept. Отладочной версии библиотеки нужно разрешить из них кидать.
Re: Конкатенация std::string_view ?!
От: T4r4sB Россия  
Дата: 30.05.23 18:56
Оценка:
Здравствуйте, Videoman, Вы писали:

V>- с чем связано такое решение в стандарте?

V>- чем такая конкатенация отличается от конкатенации с сырой С-шной строкой?

Не, ну ты спроси ещё, а почему по std::string_view нельзя делать поиск в мапе, где ключ std::string.
Это ж кресты, подожди лет 5, когда до крестокомитета дойдёт, что они опять обосрались, и ещё лет 5, когда выйдет новый крестостандарт, и ещё лет 5, когда этот стандарт будут поддерживаться всеми крестокомпиляторами.
Re[2]: Конкатенация std::string_view ?!
От: T4r4sB Россия  
Дата: 30.05.23 18:59
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>Автор оригинального proposal хотел упороться по оптимизации и сделать конкатенацию через string builder, но не смог.


Тем временем, уже много лет как есть llvm::Twine (ссылочный класс, хранит фрагменты итоговой строки), где всё смогли

https://llvm.org/doxygen/classllvm_1_1Twine.html
Re[2]: Конкатенация std::string_view ?!
От: so5team https://stiffstream.com
Дата: 30.05.23 19:14
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Не, ну ты спроси ещё, а почему по std::string_view нельзя делать поиск в мапе, где ключ std::string.


Если мапа объявлена как std::map<std::string, ValueType, std::less<>>, то можно.
Re[6]: Конкатенация std::string_view ?!
От: watchmaker  
Дата: 30.05.23 19:32
Оценка: 5 (1)
Здравствуйте, B0FEE664, Вы писали:



BFE>Я историю string_view не знаю, но по коду видно, что с string_view всё несколько странно. Например, почему operator[] не noexcept?:


Потому что noexcept Prevents Library Validation. Смотри сколько добавленных noexcept удалили. Не только из строк, а вообще из разных частей библиотеки. А string_view появился уже позже и в нём сразу не добавляли.



Но добавлю, всё это скорее относится к тем, кто пишет стандартную библиотеку, а не к тем, кто её использует. Это первым нужно тестировать правильность реализации. А пользователям это ни к чему.

Поэтому скорее всего noexcept вернётся, а авторов STL попросят писать тесты на свой код какми-нибудь другим способом.



BFE>отсюда


По этой ссылке не выписана секция Preconditions, ну или сделано это не так явном виде. Наверное потому что написано для пользователей, а не для авторов STL.
А как раз секция Preconditions и документ выше в данном случае объясняют отсутствующий в сигнатуре noexcept.


BFE>Exceptions

BFE>Does not throw

Верно. И если библиотека не хочет диагностировать баги этом в методе, то она может поставить noexcept. Как, например, это сделано в libcxx или в libstdc++.
Re[3]: Конкатенация std::string_view ?!
От: B0FEE664  
Дата: 30.05.23 22:42
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Тем временем, уже много лет как есть llvm::Twine (ссылочный класс, хранит фрагменты итоговой строки), где всё смогли

TB>https://llvm.org/doxygen/classllvm_1_1Twine.html
Сомневаюсь, что всё смогли.
Вот такое, вроде бы, судя по коду, работать не должно:
const auto to_out = "qwerty" + StringRef(std::string("asdf").substr(0, 2));
some_raw_ostream << to_out;
И каждый день — без права на ошибку...
Re[7]: Конкатенация std::string_view ?!
От: B0FEE664  
Дата: 31.05.23 09:15
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>Я историю string_view не знаю, но по коду видно, что с string_view всё несколько странно. Например, почему operator[] не noexcept?:

W>Потому что noexcept Prevents Library Validation.
Очень, очень странная аргументация. Пытаться сделать определённое поведение для ситуаций, когда поведение не определено — дурацкая затея сама по себе, а уж сделать это только для того, чтобы тестировать — вдвойне дурацкая, так как это тестирование кода, который не исполняется в release версии.
C++ это вам не Basic с его On Error Resume Next!
В конце концов — падение при бросании исключения из функции noexcept — это просто отличное поведение для undefined behavior. И вообще, отказ от оптимизации только для того, чтобы удобно было запускать тесты — это попытка заплатить за то, что не используется.

W>Но добавлю, всё это скорее относится к тем, кто пишет стандартную библиотеку, а не к тем, кто её использует. Это первым нужно тестировать правильность реализации. А пользователям это ни к чему.

В смысле? assert'ы ведущие к немедленному крашу приложения удобны для тестирования своего пользовательского кода.

В конце концов, если им так хочется ловить исключения, то нет ничего сложного, достаточно тело каждой noexcept функции обернуть в try-catch блок через макросы:
T& operator[](size_type n) noexcept
TEST_TRY
{
   assert(n < size);
   return data[n];
}
TEST_CATCH

Это конструкция для теста может разворачиваться в следующий вид:
T& operator[](size_type n) noexcept
try
{
  assert(n < size);
  return data[n];
}
catch(const assert_failed& e)
{
  global_test_resalt = Result::Failed;
}

и тогда их тест будет выглядеть так:
std::vector<int> v;
if(!v.empty()) {
return false;
}
global_test_resalt = Result::Ok;
int x = v.front();
if ( global_test_resalt != Result::Failed )
  return false;


А для реального кода, макросы TEST_TRY и TEST_CATCH определить в ничто и функция будет выглядеть так:
T& operator[](size_type n) noexcept
{
   return data[n];
}


Всё.
И никаких проблем.

W> Поэтому скорее всего noexcept вернётся, а авторов STL попросят писать тесты на свой код какми-нибудь другим способом.

Таких специалистов, действительно, стоит попросить.

BFE>>отсюда

W>По этой ссылке не выписана секция Preconditions, ну или сделано это не так явном виде. Наверное потому что написано для пользователей, а не для авторов STL.
не выписана секция Preconditions? А это тогда что:

No bounds checking is performed: the behavior is undefined if pos >= size().


W>А как раз секция Preconditions и документ выше в данном случае объясняют отсутствующий в сигнатуре noexcept.

Выглядит объяснение жалко: "Ой, это что-то новое, мы так не умеем, мы к этому не привыкли, наши тесты ломаются".
  Скрытый текст

Unfortunately the feature is so new that there is very little field experience to develop a coherent set of guidelines.



W>Верно. И если библиотека не хочет диагностировать баги этом в методе, то она может поставить noexcept.

Вот за эту цитату спасибо. Теперь понятно почему иногда есть отличие в реализации от стандарта.
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.