Prośba o code review klasy - własny separator

0

Cześć,
temat kręci wokół tego, że od czasu do czasu potrzeba wypisać liczby z różnymi separatorami. Poszukałem trochę na stacku, trochę w literaturze i napisałem coś takiego:

class separators : public std::numpunct<char>
{

public:

	explicit separators(size_t r = 0) : std::numpunct<char>(r) {}

	std::string thousands_sep;
	std::string decimal_sep;

protected:

	char do_thousands_sep() const final
	{
		return *thousands_sep.c_str();
	}
	std::string do_grouping() const final
	{
		if (thousands_sep.empty()) { return "\0"; }
		else { return "\3"; }
	}
	char do_decimal_point() const final
	{
		return *decimal_sep.c_str();
	}
};

potem w praktyce używam jej w tej sposób:

separators * s = new separators;

TCHAR szSep[8];
std::stringstream ss;
			
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, 8);
s->thousands_sep = szSep;

// ... tutaj po drodze jakaś matematyka dla wyniku

ss.imbue(std::locale(std::locale(), s));
ss << std::fixed << math_result;

if (ss.good())
{
    //... jak wszystko jest ok, to zapisz ten wynik w formie tekstowej
}
   

Teraz problem z jakim się borykam:
Kiedy zbuduję wszystko w release jest w porządku, natomiast kiedy chcę przeprowadzić debugowanie, to dochodząc do if (ss.good()) dostaję błąd _CrtIsValidHeapPointer(block)

W projekcie jest trochę MFC, trochę boosta, no i STL. Nie mogę ustalić jaki jest powód takiego zachowania. Być może czegoś nie doczytałem i tak teraz się nie robi, a może czegoś brakuje, chociaż kod robi robotę i wyrzuca liczby tak sformatowane jak się tego oczekuje. Projekt jest z Visual Studio 2017 (v141), standard dopuszczalny C++14

0
BartoSAS napisał(a):

Cześć,
temat kręci wokół tego, że od czasu do czasu potrzeba wypisać liczby z różnymi separatorami.

Od tego jest std::locale które żle używasz.
https://en.cppreference.com/w/cpp/locale/locale

https://godbolt.org/z/cPqWb3YTb

0
BartoSAS napisał(a):

W projekcie jest trochę MFC,

To Elvis jeszcze żyje ?
:)

0

@MarekR22: czyli ta cała klasa, którą napisałem jest do zezłomowania? Plus u Ciebie w przykładzie z góry wiesz jaki format separatorów będzie, ja dowiaduję się "w ostatniej chwili".

@ZrobieDobrze: tak, ma się całkiem dobrze i o dziwo generuje $$$

0

@MarekR22: To tak tylko się upewnię - sugerujesz, żeby nie robić tak separators * s = new separators; dla "własnego separatora tysięcy"? No bo nawet jak użyję locale jak należy, to ta jedna sprawa pozostaje nierozwiązana.

Nowe informacje:
Przy debugowaniu kodu przy używaniu tego rozwiązania z pierwszego postu trafiam na kod:

_CRT_SECURITYCRITICAL_ATTRIBUTE
void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK);
    #else
    free(block);
    #endif
}
0
BartoSAS napisał(a):

@MarekR22: To tak tylko się upewnię - sugerujesz, żeby nie robić tak separators * s = new separators; dla "własnego separatora tysięcy"? No bo nawet jak użyję locale jak należy, to ta jedna sprawa pozostaje nierozwiązana.

Nowe informacje:
Przy debugowaniu kodu przy używaniu tego rozwiązania z pierwszego postu trafiam na kod:

_CRT_SECURITYCRITICAL_ATTRIBUTE
void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK);
    #else
    free(block);
    #endif
}

co znaczy "to ta jedna sprawa pozostaje nierozwiązana."?

Czy chodzi o to:
std::locale::locale - cppreference.com

Notes

Overload 7 is typically called with its second argument, f, obtained directly from a new-expression: the locale is responsible for calling the matching delete from its own destructor.

0

Jedna sprawa, miałem na myśli "customowy separator tysięcy". Chyba tak, dodatkowo trafiłem jeszcze na taki artykuł, podejrzewam, że to może być dosłownie ten sam przypadek, problem.

Gdy tylko debugera zmotywowałem do załadowania wszystkiego, co znał, to problem z tym wyjątkiem już wyszedł na linii
ss << std::fixed << math_result;

Nie wiem, czy wystarczająco dobrze to ujmę: do jednej dll-ki są wkompilowane statycznie pozostałe liby, a to wszystko jest pomieszane z podpiętym dynamicznie boostem (BOOST_ALL_DYN_LINK). Nie wiem, czy to istotne, ale wersja debugowa jest budowana w wariancie MDd.

Nowe informacje:
Wyrzuciłem na chwilę linię z ustawieniem własnego separatora. Nawet jak ustawiłem po prostu:
ss << 21.37;
to i tak zachowywało się identycznie. Debuger ląduje w _free_dbg(block, _UNKNOWN_BLOCK i pada :/

1 użytkowników online, w tym zalogowanych: 0, gości: 1