Use absl's locale-independent conversion functions in XPRESS MPSolver interface by flomnes · Pull Request #4382 · google/or-tools
Using such functions as std::stoi, std::stod, etc. caused us a lot of trouble because these functions are locale dependent, as illustrated below
#include <iostream> #include <locale> #include <string> void convert(std::string locale) { std::string value = "9.81"; if (std::setlocale(LC_ALL, locale.c_str())) { double converted = std::stod(value); std::cout << "locale " << locale << " converted to " << converted << std::endl; } else { std::cout << "locale set failed for " << locale << std::endl; } } int main() { convert("C"); convert("fr_FR.utf8"); // OUTPUT // locale C converted to 9.81 // locale fr_FR.utf8 converted to 9 }
At first, we thought that using ScopedLocale would allow us to temporarily use the "C" locale, but this approach has multiple problems
- It's not thread-safe. For example calling
std::stodwhen the locale is being changed throughstd::setlocaleis undefined behavior source. - C is hard,
const char*pointers easily become dangling or invalid without the caller knowing
struct ScopedLocale { ScopedLocale() { oldLocale = std::setlocale(LC_NUMERIC, nullptr); auto newLocale = std::setlocale(LC_NUMERIC, "C"); CHECK_EQ(std::string(newLocale), "C"); } ~ScopedLocale() { std::setlocale(LC_NUMERIC, oldLocale); } private: const char* oldLocale; };
We ran into an issue where the locale wasn't properly restored after using MPSolver::XpressInterface. So we decided to use absl's locale independent functions to perform that task.