Проверьте, использует ли версия libstdc++ std::string, совместимую с C++11.

Я пишу некоторый код C++11, который делает предположения о природе std::string, которые являются допустимыми, но представляют поведение, которое было изменено в C++11. Раньше реализация basic_string в libstdc++ соответствовала требованиям 98/03, но не более строгим требованиям C++11.

Насколько я понимаю, libstdc++ исправила проблемы с basic_string. Проблема в том, что существует множество версий библиотеки, используемых людьми, в которых это исправление не реализовано. И мой код может незаметно дать сбой многими неприятными способами на них.

Я хотел бы иметь static_assert огонь, если пользователь попытается скомпилировать мою библиотеку с этими несовместимыми версиями libstdc++. Как определить версию и, что не менее важно, какую версию искать?


person Nicol Bolas    schedule 19.12.2015    source источник
comment
можешь озвучить свои предположения?   -  person Tobias Langner    schedule 20.12.2015
comment
Я считаю, что это требуется даже в С++ 03. COW должен сохранить это свойство.   -  person Puppy    schedule 20.12.2015
comment
@Puppy: Извините, я сказал это неправильно. Лучше просто посмотреть здесь. Что-то такое.   -  person Nicol Bolas    schedule 20.12.2015
comment
Не могли бы вы проверить, завершается ли std::string нулем? Если это так, вы знаете, что он соответствует требованиям C++11 согласно C++0x FDIS 21.4.7.1/1.   -  person erip    schedule 20.12.2015
comment
@erip: Это не то, что вы можете static_assert делать. Кроме того, в C++98/03 было бы неопределенным поведением пытаться получить доступ к символу терминатора, поэтому он может работать даже с ними.   -  person Nicol Bolas    schedule 20.12.2015
comment
@NicolBolas зачем тебе static_assert? Я знаю, что они в порядке, но вам, вероятно, также нужны модульные тесты, поэтому запуск теста также должен быть хорошим.   -  person Tobias Langner    schedule 20.12.2015
comment
@TobiasLangner: Потому что большинство моих пользователей будут компилировать мою библиотеку, а не мои тесты.   -  person Nicol Bolas    schedule 20.12.2015
comment
@NicolBolas: это не эквивалентно - вызов s[0] в этом ответе не является const-квалифицированным.   -  person Puppy    schedule 20.12.2015
comment
Затем @NicolBolas добавьте тест к инициализации в режиме отладки. Не должно занять много времени. Возьмите пример из ссылки выше и сделайте это в обоих направлениях, чтобы обнаружить COW.   -  person Tobias Langner    schedule 20.12.2015
comment
@Puppy: я никогда не говорил, что ссылка эквивалентна; вот почему я сказал, что сказал это неправильно.   -  person Nicol Bolas    schedule 20.12.2015
comment
@TobiasLangner: Хм, спасибо, но нет, спасибо.   -  person Nicol Bolas    schedule 20.12.2015
comment
@Tobias: Вы делаете предположение, что его библиотека на самом деле имеет некоторую одноразовую инициализацию.   -  person Puppy    schedule 20.12.2015


Ответы (2)


Новый std::string, совместимый с C++11, был представлен с новым (двойным) ABI в GCC 5 (раздел библиотеки времени выполнения журнал изменений).

Макрос _GLIBCXX_USE_CXX11_ABI решает, используется ли старый или новый ABI, поэтому просто проверьте его:

#if _GLIBCXX_USE_CXX11_ABI

Конечно, это относится только к libstdС++.

person user1942027    schedule 19.12.2015

#include <string>

static_assert(sizeof(std::string) != sizeof(void*), "using ref-counted string");

int
main()
{
}

Демонстрация: http://melpon.org/wandbox/permlink/P8LB79Cy6ASZlKuV

Этот тест использует внутреннюю работу всех известных реализаций std::lib std::string и, в частности, реализации gcc.

gcc refcounted string состоит из одного указателя на динамически выделяемую структуру, которая содержит размер, емкость, счетчик ссылок и данные строки. Скотт Мейерс делает хороший обзор строковых реализаций в Effective STL, который был точен для временных рамок 2001 года. Я полагаю (могу ошибаться), что "реализация C" в пункте 15 этой книги - это gcc std::string.

Для реализаций коротких строк (в значительной степени предписанных C++11) string больше не может состоять из одного указателя на стек. Реализация Скотта D — это наш первый взгляд на реализацию коротких строк той эпохи. Это VS/Dinkumware string. Сам sizeof(string) будет содержать некоторый буфер данных для хранения строковых данных без распределения.

С помощью этой короткой программы можно понять, что делают разные реализации:

#include <iostream>
#include <string>

int
main()
{
    std::string s;
    std::cout << "word size is           " << sizeof(void*)/sizeof(char) << '\n';
    std::cout << "sizeof string is       " << sizeof(s) << '\n';
    std::cout << "short string buffer is " << s.capacity() << '\n';
}

Это распечатывает размер слова, обычно 4 или 8 (32 бита / 64 бита), поскольку по крайней мере одна реализация (libc++) меняет свои характеристики на этой аппаратной функции. Затем он выводит sizeof(string), которое будет кратно размеру слова, а затем capacity() пустого string, которое будет размером буфера коротких строк, если он существует.

Вот несколько неполный опрос:

gcc/libstdc++ 4.8

word size is           8
sizeof string is       8
short string buffer is 0

gcc/libstdc++ 5.2

word size is           8
sizeof string is       32
short string buffer is 15

clang/libc++ -arch i386 OS X

word size is           4
sizeof string is       12
short string buffer is 10

clang/libc++ -arch x86_64 OS X

word size is           8
sizeof string is       24
short string buffer is 22

VS-2015

word size is           4
sizeof string is       24
short string buffer is 15

В этом обзоре только gcc/libstdc++ 4.8 явно не использует оптимизацию коротких строк. И только gcc/libstdc++ 4.8 имеет sizeof(string) == 1 word. И это фактически единственная реализация в этом обзоре, использующая подсчет ссылок.

В общем, этот тест для std::string libstdc++ не переносим. Но по спецификации это не обязательно. Мы можем воспользоваться известной историей развития gcc в этой области. Спецификация (вопрос) говорит, что она должна работать только на gcc libstdc++.

person Howard Hinnant    schedule 20.12.2015
comment
Можете ли вы кратко объяснить, почему это должно сработать? Имеют ли строки COW только один элемент данных void* (частный) и, конечно же, никаких виртуальных функций? - person vsoftco; 20.12.2015
comment
Спасибо, отличное объяснение. - person vsoftco; 20.12.2015
comment
Чтобы расширить обзор, строки VS-2013 имеют ту же структуру, что и строки VS-2015. В VS-2010 строки имеют дополнительный размер слова больше (из-за отсутствия оптимизации нулевого размера std::allocator). Я составил сводную таблицу для 64-битных версий различных стандартные библиотеки, которые также включают другие детали, такие как стратегия роста. - person dmr195; 07.02.2016