Объекты STL используют языковой стандарт C Runtime Library для преобразования с плавающей запятой при использовании _ENABLE_PER_THREAD_LOCALE? - PullRequest
1 голос
/ 10 ноября 2010

Языковой стандарт времени выполнения C устанавливается setlocale.Языковой стандарт стандартной библиотеки C ++ (STL) устанавливается классом std::locale и может устанавливаться для отдельных объектов STL, таких как std :: istringstream и т. Д.

Функция _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) позволяет установить языковой стандарт C Runtimeдля каждого потока.

К сожалению, кажется, что объекты STL в потоках, в которых включено _configthreadlocale(_ENABLE_PER_THREAD_LOCALE), используют языковой стандарт времени выполнения C.Или, по крайней мере, используя десятичную точку локали C Runtime.

В потоках без _ENABLE_PER_THREAD_LOCALE проблем нет.

Нечто подобное было задано Paavo в 2008 году, но без ответов: _configthreadlocale и localeconv

Следующий код показывает проблему:

//Enable per thread locale in current thread  
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  

//Create istringstream object  
std::istringstream LibraryStream;  
//Create double object  
double Value = 0;  
//Create std::locale object with "C" locale ("." as decimal point)  
std::locale StreamLoc("C");  
//Set C Runtime locale to danish ("," as decimal point)  
setlocale(LC_ALL, "danish");  

//Set the "C" locale on the istringstream object  
LibraryStream.imbue(StreamLoc);  
//Get the locale of the istringstream object for test (returns "C" as expected)  
std::locale NewStreamLoc = LibraryStream.getloc();  

//Set floating point string with "C" locale decimal point in istringstream object  
LibraryStream.str("60.258351");  
//Convert the string to double  
LibraryStream >> Value;  

//Now the expected value of "Value" is 60.258351, but it is 60.000  
//when debugging the conversion, I can see that "," is used as decimal point  

Кто-нибудь сталкивался с этим раньше?Я делаю что-то неправильно?Есть ли предложения по решениям?

Заранее спасибо / TEB

Ответы [ 3 ]

3 голосов
/ 10 ноября 2010

Поскольку стандартная библиотека C ++ только недавно получила знания о потоках, эта очевидная дихотомия меня не удивляет. Существует исчерпывающее обсуждение того, что происходит в различных сценариях (для Microsoft, но, кажется, полезно в качестве общего фона) здесь .

В итоге:

Чтобы изменить язык с помощью C ++ Runtime Library, используйте языковой стандарт. Вызывая метод locale :: global, вы меняете локаль в каждой теме который явно не включен локаль для потока Чтобы изменить локаль в одной теме или части приложения, просто создайте экземпляр объекта локали в этом поток или часть кода.

1 голос
/ 10 ноября 2010

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

На Многопоточность и локали В статье Knowlegde Base отмечено:

Вызов локали :: глобальные изменения языковой стандарт для C ++ Библиотека и библиотека времени выполнения C. Однако, вызывая только setlocale меняет локаль для C Runtime Библиотека; Стандартная библиотека C ++ не затронут.

Вы действительно используете C ++ Std Lib, поэтому мне показалось, что вам нужно вызвать locale::global(). Когда я это сделал, возвращаемое значение соответствует ожидаемому. Вот мой пример кода:

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{

    //Enable per thread locale in current thread  
    int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");  

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  
    locale::global(StreamLoc);
    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

        //Now the expected value of "Value" is 60.258351, but it is 60.000  
    //when debugging the conversion, I can see that "," is used as decimal point  
}
0 голосов
/ 11 ноября 2010

Хороший вопрос, Джон Диблинг.Я проверил это, и оператор >> Value использует локаль в потоке, а не глобальную локаль.Это было проверено на примере ниже:

_configthreadlocale (_ENABLE_PER_THREAD_LOCALE), удалено
locale :: global (locale ("danish")); добавлено для установки глобальной языковой стандарт Std lib

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{
    //Enable per thread locale in current thread  
    //int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");

    //Set Std lib global locale to "danish"
    locale::global(locale("danish"));

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  

    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

    //In this case the value of "Value" is 60.258351, as expected and thus  
    //the "C" locale was use for conversion  
}

Я предполагаю, что на данный момент вывод состоит в том, что объекты STL в потоках, в которых включен _configthreadlocale (_ENABLE_PER_THREAD_LOCALE), действительно используют языковой стандарт времени выполнения C.

Можно обойти это, установив локаль Std lib и локаль C Runtime с помощью вызова locale :: global ().Но так как языковой стандарт Std lib не является потокобезопасным и не подвержен влиянию _ENABLE_PER_THREAD_LOCALE, мы все равно можем столкнуться с проблемами многопоточности с этим обходным решением.

...