From 6155d5242f29454080e17a261bf04cb308036706 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 10 Sep 2026 17:58:03 +0200 Subject: [PATCH] Stop the serializer from holding onto std::localeconv()'s pointer loc was only ever read twice, immediately, to seed thousands_sep and decimal_point; nothing else in the class used it. A local in the constructor body serves the same purpose without keeping the pointer around for the serializer's lifetime. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/output/serializer.hpp | 17 +++++++++-------- single_include/nlohmann/json.hpp | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 6f54d0094..e89a21a15 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -82,15 +82,18 @@ class serializer const std::size_t indent_step_ = 0, error_handler_t error_handler_ = error_handler_t::strict) : o(std::move(s)) - , loc(std::localeconv()) - , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) - , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) , indent_char(ichar) , pretty_print(pretty_print_) , ensure_ascii(ensure_ascii_) , indent_step(indent_step_) , error_handler(error_handler_) - {} + { + // only used here to seed thousands_sep/decimal_point, so a local + // suffices and the serializer does not need to hold onto it + const auto* loc = std::localeconv(); + thousands_sep = loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep)); + decimal_point = loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point)); + } // deleted because of pointer members serializer(const serializer&) = delete; @@ -1674,12 +1677,10 @@ class serializer /// a (hopefully) large enough character buffer std::array number_buffer{{}}; - /// the locale - const std::lconv* loc = nullptr; /// the locale's thousand separator character - const char thousands_sep = '\0'; + char thousands_sep = '\0'; /// the locale's decimal point character - const char decimal_point = '\0'; + char decimal_point = '\0'; /// string buffer std::array string_buffer{{}}; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 3045c96e3..39036000c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -21430,15 +21430,18 @@ class serializer const std::size_t indent_step_ = 0, error_handler_t error_handler_ = error_handler_t::strict) : o(std::move(s)) - , loc(std::localeconv()) - , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) - , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) , indent_char(ichar) , pretty_print(pretty_print_) , ensure_ascii(ensure_ascii_) , indent_step(indent_step_) , error_handler(error_handler_) - {} + { + // only used here to seed thousands_sep/decimal_point, so a local + // suffices and the serializer does not need to hold onto it + const auto* loc = std::localeconv(); + thousands_sep = loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep)); + decimal_point = loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point)); + } // deleted because of pointer members serializer(const serializer&) = delete; @@ -23022,12 +23025,10 @@ class serializer /// a (hopefully) large enough character buffer std::array number_buffer{{}}; - /// the locale - const std::lconv* loc = nullptr; /// the locale's thousand separator character - const char thousands_sep = '\0'; + char thousands_sep = '\0'; /// the locale's decimal point character - const char decimal_point = '\0'; + char decimal_point = '\0'; /// string buffer std::array string_buffer{{}};