std::collate::transform вызвал ошибку сегментации

Когда я запускаю следующий исходный код, я получаю «Ошибка сегментации (дамп ядра)» в строке № 3.

char s[] = "helloworld";
const std::collate<char>* pc = &std::use_facet<std::collate<char> >(std::locale("en_US"));
std::string str = pc->transform(s, s + std::strlen(s));
std::cout << str.length() << "," << str << std::endl;

Если я заменю строку № 2 на

const std::collate<char>* pc = new std::collate_byname<char>("en_US");

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

PS: компилятор c++ — g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3).


person songyuanyao    schedule 17.02.2014    source источник


Ответы (1)


Чтение документов use_facet:

Ссылка, возвращаемая этой функцией, действительна до тех пор, пока существует любой объект std::locale, реализующий Facet.

Вы создаете временный std::locale в своем коде, так что временный уничтожается в конце выражения, и у вас остается оборванный указатель. Вот так должно работать:

char s[] = "helloworld";
std::locale en_US("en_US");
const std::collate<char>* pc = &std::use_facet<std::collate<char> >(en_US);
std::string str = pc->transform(s, s + std::strlen(s));
std::cout << str.length() << "," << str << std::endl;
person Angew is no longer proud of SO    schedule 17.02.2014
comment
Я ошибочно полагал, что std::locale("en_US") будет глобальным объектом, но на самом деле глобальными являются только std::locale() и std::locale::classic(). - person songyuanyao; 17.02.2014
comment
@songyuanyao Точнее говоря: объект std::locale - это просто тупой (какой-то) набор указателей на фасеты, причем сами фасеты подсчитываются по ссылкам. classic() возвращает фактическую ссылку C++ на глобальный экземпляр C-локали, в то время как пустой ctor std::locale возвращает копию глобальной локали (увеличивая счетчик ссылок на ее фасетах). Построение другой локали даст вам объект локали, грани которого (потенциально) используются только этим объектом — ref. count 1. Потерять этот объект, и грани опустятся до 0 и будут уничтожены. - person Angew is no longer proud of SO; 17.02.2014