Учитывая, что:
1) Стандарт C ++ 03 никак не касается существования потоков
2) Стандарт C ++ 03 оставляет реализациям решать, следует ли std::string
использовать семантику Copy-on-Write в своем конструкторе копирования
3) Семантика копирования при записи часто приводит к непредсказуемому поведению в многопоточной программе
Я прихожу к следующему, казалось бы, противоречивому выводу:
Вы просто не можете безопасно и удобно использовать std :: string в многопоточной программе
Очевидно, что ни одна структура данных STL не является поточно-ориентированной. Но, по крайней мере, например, с помощью std :: vector, вы можете просто использовать мьютексы для защиты доступа к вектору. С реализацией std :: string, которая использует COW, вы даже не можете надежно сделать это, не редактируя семантику подсчета ссылок глубоко внутри реализации поставщика.
Пример из реального мира:
В моей компании у нас есть многопоточное приложение, которое было тщательно протестировано модульно и проходило через Valgrind бесчисленное количество раз. Приложение работало месяцами без каких-либо проблем. Однажды я перекомпилирую приложение на другой версии gcc, и внезапно я все время получаю случайные ошибки. Valgrind теперь сообщает о недопустимых обращениях к памяти глубоко внутри libstdc ++, в конструкторе копирования std :: string.
Так в чем же решение? Ну, конечно, я мог бы ввести typedef std::vector<char>
как строковый класс - но на самом деле это отстой. Я мог бы также ждать C ++ 0x, который, как я молюсь, потребует от разработчиков отказаться от COW. Или, (содрогается), я мог бы использовать собственный класс строки. Лично я всегда против разработчиков, которые реализуют свои собственные классы, когда существующая библиотека будет работать хорошо, но, честно говоря, мне нужен строковый класс, который, я уверен, не использует семантику COW; и std :: string просто не гарантирует этого.
Прав ли я, что std::string
просто невозможно надежно использовать вообще в переносимых многопоточных программах? И что такое хороший обходной путь?