Re: Problem with heap and malloc()/free()
"Giovanni Dicanio" <giovanni.dicanio@invalid.com> ha scritto nel messaggio
news:uUjs6AaXIHA.4196@TK2MSFTNGP04.phx.gbl...
A first step could be to stop using those raw C-like arrays, both malloc
and new[], and start using a robust C++ container class, like std::vector.
If you add an std::vector instance as a data member (instead of the raw
wchar_t * pointer), std::vector will take care of proper copy and cleanup.
If you want to compare using std::vector container as data member vs. how to
implement deep-copy and cleanup and managing C++ raw arrays using
new[]/delete[] , you might find interesting the following "test" project (I
developed it with Visual C# 2008 Express, so you can freely open/read/modify
it):
http://www.geocities.com/giovanni.dicanio/temp/TestStringHandler_20080123.zip http://tinyurl.com/29k8lnThe class that implements StringHandler using std::vector is inStringHandler.cpp/.h; the other class (which does lot more work, and is moreerror prone) is in StringHandlerRaw.cpp/.h .The test I've done seems to work fine; I've tried copying class instances,calling operator= and copy constructor, etc. (but a deeper test could bedone).The implementation of these classes is also at the end of this post (ofcourse, the code could be improved).HTH,Giovanni----///////////////////////////////////////////////////////////////////////////////// StringHandler.h///////////////////////////////////////////////////////////////////////////////#pragma once//-----------------------------------------------------------------------------// String handler implementation// (uses std::vector container)//-----------------------------------------------------------------------------class StringHandler{public: // Init the instance StringHandler(); // Get the wchar_t pointer (string). // Return NULL if there is no string set const wchar_t * GetString() const; // Assign a new string void SetString( const wchar_t * s ); // Convert a string from UTF-8 to UTF-16, and assign it // to this instance. // Return true on success, false on error (e.g. some conversion error) bool SetUTF8String( const BYTE * utf8 ); // Clear the string void Clear(); // // IMPLEMENTATION //private: typedef std::vector< wchar_t > WCharArray; // Stores Unicode UTF-16 string in a std::vector< wchar_t > WCharArray m_wstr; // Assign current array from input string. // If input pointer is NULL, clear the data member array void CopyFrom( const wchar_t * source );};//// INLINE IMPLEMENTATIONS//inline const wchar_t * StringHandler::GetString() const{ if ( ! m_wstr.empty() ) return &(m_wstr[0]); else return NULL;}inline void StringHandler::SetString( const wchar_t * s ){ CopyFrom( s );}inline void StringHandler::Clear(){ m_wstr.clear();}///////////////////////////////////////////////////////////////////////////////[-----------------------------------------------------------------------------]///////////////////////////////////////////////////////////////////////////////// StringHandler.cpp///////////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "StringHandler.h"StringHandler::StringHandler(){ // Nothing to do here}bool StringHandler::SetUTF8String( const BYTE * utf8 ){ // Flags for ::MultiByteToWideChar conversion DWORD conversionFlags = 0; // default // Input string pointer LPCSTR source = reinterpret_cast<LPCSTR>( utf8 ); // Ask the size of the destination buffer, in WCHARs // (including terminating null character) int destBufferWChars = ::MultiByteToWideChar( CP_UTF8, // code page conversionFlags,// conversion flags source, // pointer to source string to convert -1, // the input string is null-terminated NULL, // don't need it now 0 // ask to return the buffer size in WCHARs ); // If the function returns 0, there is an error... if ( destBufferWChars == 0 ) return false; // Allocate memory to store the new string WCharArray destString( destBufferWChars ); // Do the conversion int result = ::MultiByteToWideChar( CP_UTF8, // code page conversionFlags,// conversion flags source, // pointer to source string to convert -1, // the input string is null-terminated &(destString[0]), // destination string buffer destBufferWChars// destination buffer size in WCHARs ); if ( result == 0 ) return false; // Error // Attach the new string m_wstr = destString; // All right return true;}void StringHandler::CopyFrom( const wchar_t * source ){ if ( source == NULL ) { m_wstr.clear(); return; } // Get the number of wchar_t's in the string, including terminating null size_t bufferWChars = ::wcslen( source ) + 1; // Resize the array to store this data m_wstr.resize( bufferWChars ); // Copy data from source to destination ::CopyMemory( &(m_wstr[0]), source, bufferWChars * sizeof(wchar_t) );}///////////////////////////////////////////////////////////////////////////////[-----------------------------------------------------------------------------]///////////////////////////////////////////////////////////////////////////////// StringHandleRaw.h///////////////////////////////////////////////////////////////////////////////#pragma once//-----------------------------------------------------------------------------// String handler implementation ("raw" version)// (uses a raw C++ wchar_t * pointer, but provides proper deep-copysemantic)//-----------------------------------------------------------------------------class StringHandlerRaw{public: StringHandlerRaw(); StringHandlerRaw( const StringHandlerRaw & source ); virtual ~StringHandlerRaw(); StringHandlerRaw & operator=( const StringHandlerRaw & source ); // Get the wchar_t pointer (string) const wchar_t * GetString() const; // Assign a new string void SetString( const wchar_t * s ); // Convert a string from UTF-8 to UTF-16, and assign it // to this instance. // Return true on success, false on error (e.g. some conversion error) bool SetUTF8String( const BYTE * utf8 ); // Clear the string void Clear(); // // IMPLEMENTATION //private: // Pointer to the Unicode UTF-16 string wchar_t * m_wstr; // Initialize the object void CommonConstruct(); // Delete the object (release resources) void Cleanup(); // Deep-copy from a source string. // Returns the deep-copy result. // If the input string pointer is NULL, returns NULL. wchar_t * CopyFrom( const wchar_t * source );};//// INLINE IMPLEMENTATIONS//inline const wchar_t * StringHandlerRaw::GetString() const{ return m_wstr;}inline void StringHandlerRaw::Clear(){ Cleanup();}inline void StringHandlerRaw::CommonConstruct(){ m_wstr = NULL;}///////////////////////////////////////////////////////////////////////////////[-----------------------------------------------------------------------------]///////////////////////////////////////////////////////////////////////////////// StringHandlerRaw.cpp///////////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "StringHandlerRaw.h"StringHandlerRaw::StringHandlerRaw(){ CommonConstruct();}StringHandlerRaw::StringHandlerRaw( const StringHandlerRaw & source ){ CommonConstruct(); m_wstr = CopyFrom(source.m_wstr);}StringHandlerRaw::~StringHandlerRaw(){ Cleanup();}StringHandlerRaw & StringHandlerRaw::operator=( const StringHandlerRaw &source ){ if ( &source != this ) // avoid X = X { // Deep-copy wchar_t * newString = CopyFrom(source.m_wstr); // Release current resources Cleanup(); // Set the new one m_wstr = newString; } return *this;}void StringHandlerRaw::SetString( const wchar_t * s ){ // Do a deep copy of input string wchar_t * copy = CopyFrom(s); // Release current resources Cleanup(); // Set the new one m_wstr = copy;}bool StringHandlerRaw::SetUTF8String( const BYTE * utf8 ){ // Flags for ::MultiByteToWideChar conversion DWORD conversionFlags = 0; // default // Input string pointer LPCSTR source = reinterpret_cast<LPCSTR>( utf8 ); // Ask the size of the destination buffer, in WCHARs // (including terminating null character) int destBufferWChars = ::MultiByteToWideChar( CP_UTF8, // code page conversionFlags,// conversion flags source, // pointer to source string to convert -1, // the input string is null-terminated NULL, // don't need it now 0 // ask to return the buffer size in WCHARs ); // If the function returns 0, there is an error... if ( destBufferWChars == 0 ) return false; // Allocate memory to store the new string wchar_t * destString = new wchar_t[ destBufferWChars ]; // Do the conversion int result = ::MultiByteToWideChar( CP_UTF8, // code page conversionFlags,// conversion flags source, // pointer to source string to convert -1, // the input string is null-terminated destString, // destination string buffer destBufferWChars// destination buffer size in WCHARs ); if ( result == 0 ) { // Cleanup allocated memory delete destString; destString = NULL; // Error return false; } // Free existing string Cleanup(); // Attach the new string m_wstr = destString; // All right return true;}void StringHandlerRaw::Cleanup(){ if ( m_wstr != NULL ) { delete [] m_wstr; // Avoid dangling references m_wstr = NULL; }}wchar_t * StringHandlerRaw::CopyFrom( const wchar_t * source ){ // Special case of NULL input if ( source == NULL ) return NULL; // Get the number of wchar_t's in the string, including terminating null size_t bufferWChars = ::wcslen( source ) + 1; // Allocate memory for destination (copy) string wchar_t * copy = new wchar_t[ bufferWChars ]; // Copy data from source to destination ::CopyMemory( copy, source, bufferWChars * sizeof(wchar_t) ); // Return the deep copy return copy;}///////////////////////////////////////////////////////////////////////////////