• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 600
  • Last Modified:

How to solve memory leak problem with static std:base_string variable?

Hi Experts,
I have a class as below:
//MyClass.h
                typedef std::basic_string<TCHAR> String;
            class MyClass
            {
            public:
                  static String ISO8601_DATE_FORMAT;
                  static String ABS_TIME_DATE_FORMAT;
                  static String DATE_AND_TIME_DATE_FORMAT;
                       String getDateFormat();
                }
//MyClass.cpp
String MyClass::ISO8601_DATE_FORMAT = _T("ISO8601");
String MyClass::ABS_TIME_DATE_FORMAT = _T("ABSOLUTE");
String MyClass::DATE_AND_TIME_DATE_FORMAT = _T("DATE");

String MyClass::getDateFormat(){
   return "";
}

BUT it has problem about memory leak when I run my app even if I have not used MyClass as below:

 Data: <  D A T E       > CD 00 44 00 41 00 54 00 45 00 00 00 CD CD CD CD
{52} normal block at 0x00AB1B30, 66 bytes long.
 Data: <  A B S O L U T > CD 00 41 00 42 00 53 00 4F 00 4C 00 55 00 54 00
{51} normal block at 0x00AB1E20, 66 bytes long.
 Data: <  I S O 8 6 0 1 > CD 00 49 00 53 00 4F 00 38 00 36 00 30 00 31 00
{46} normal block at 0x00AB1D30, 33 bytes long.

So, How i can resolve this problem? How to free a std:base_string? do it needs to free?
Why it has memory leak about this?

Pls help me soon
Thank in advance!

0
Mobinex
Asked:
Mobinex
  • 9
  • 5
  • 2
  • +2
1 Solution
 
ikeworkCommented:
the memory-check is performed before the global objects (the static strings) are destroyed, but they will be destroyed at the end of the programm..

the strings look like data which will never be changed, then you could use const char's, they dont need allocation:


class MyClass
{
public:
    static const TCHAR *ISO8601_DATE_FORMAT;
    static const TCHAR *ABS_TIME_DATE_FORMAT;
    static const TCHAR *DATE_AND_TIME_DATE_FORMAT;
};

const TCHAR *MyClass::ISO8601_DATE_FORMAT = _T("ISO8601");
const TCHAR *MyClass::ABS_TIME_DATE_FORMAT = _T("ABSOLUTE");
const TCHAR *MyClass::DATE_AND_TIME_DATE_FORMAT = _T("DATE");


ike
0
 
ikeworkCommented:
just tested it with vc8 .. it doesnt give me this error ..
which vs-version do you use and where do you call _CrtDumpMemoryLeaks () ?
0
 
itsmeandnobodyelseCommented:
>>>> just tested it with vc8 .. it doesnt give me this error ..
It will, if using the DEBUG_NEW macro in the cpp.

>>>> static const TCHAR *
That is a very good workaround and should solve the issue.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
ikeworkCommented:
>>>> just tested it with vc8 .. it doesnt give me this error ..
>> It will, if using the DEBUG_NEW macro in the cpp.

DEBUG_NEW is defined and to test it i made a real memory-leak by

int *p = new int;

and it was reported ..
0
 
MobinexAuthor Commented:
Yes, for this example we can use const TCHAR to solve this problem, but I have orther problem that I can not use const TCHAR with this case,

Is it OK to use static class or static variables event if the memory check detected memory leak but it will be OK (it is really not has memory leak after the app finished)?

My problem as below:
//MyClass.h
class MyClass
{
public:
      MyClass(const String& name);
      virtual MyClass& newInstance() const;
      const String& toString() const;
      const String& getName() const;
      static const MyClass& forName(const String& className);
protected:
      static void registerClass(const MyClass * myClass);
      String name;
};
MyClass::MyClass(const String& name) : name(name)
{
}

//TestClass.h
class TestClass{

//defined DECLARE_MY_OBJECT
public:
      class ClassTestClass : MyClass
      {
            public:
            ClassTestClass: MyClass(_T("TestClass")) {
            }
            virtual MyClass& newInstance() const
            {
                  return new TestClass();
            }
      };
      virtual const MyClass& getClass() const;
        static MyClass& getStaticClass();
        static ClassTestClass theClassTestClass;
}
//end defined DECLARE_MY_OBJECT

//defined IMPLEMENT_MY_OBJECT
TestClass::ClassTestClass TestClass::theClassTestClass;
const MyClass& TestClass::getClass() const { return theClassTestClass }
const MyClass& TestClass::getStaticClass() { return theClassTestClass }
//end IMPLEMENT_MY_OBJECT

from //MyClass.h I have defined DECLARE_MY_OBJECT and DECLARE_MY_OBJECT macro (I have detailed the code)

from //TestClass.h I have use DECLARE_MY_OBJECT
and in the top of //TestClass.cpp I have used IMPLEMENT_MY_OBJECT

When I start my app even if I have not yet used MyClass or TestClass, with debugger I see constructor of MyClass called and the name is assigned to TestClass name

When I stop the app, memory check detecked the memory leak about

Data: <  T e s t C l a s s       > CD 00 44 00 41 00 54 00 45 00 00 00 CD CD CD CD
{52} normal block at 0x00AB1B30, 66 bytes long.

The same with above problem.

This is just my example, I have implement more class the extends MyClass and have defined DECLARE and IMPLEMENT as above, all they are give me the same problem about name memory leak.

Can you help me to clear what wrong? it just has memory leak because memory check is performed  before this destroyed? is it OK?
Do we need solve this problem and how to solve problem?

Pls give me a hand again.

Thank in advance!
0
 
ikeworkCommented:
i think the problem is the "new TestClass".. you have to delete it as well

            virtual MyClass& newInstance() const
            {
                  return new TestClass();
            }
0
 
Infinity08Commented:
>> it just has memory leak because memory check is performed  before this destroyed?

Yes, that's pretty much it. The life of a static is the entire duration of the application. The memory check shouldn't report it as a memory leak, and if it does, you can just ignore it.

To put you at ease maybe : the operating system is going to reclaim all memory (including leaked memory) the moment the application is stopped.
0
 
ikeworkCommented:
every instance you create with new has to be deleted:

MyClass &instance1 = newInstance();


...

delete &instance1;

and make sure you take the reference and not a copy, since your function "newInstance" returns not the pointer but a reference. this would just make a copy:

MyClass instance1 = newInstance();

and the delete would fail .. so better change the return-value of "newInstance()" to a pointer:

 virtual MyClass* newInstance() const
 {
     return new TestClass();
 }


0
 
MobinexAuthor Commented:
Hi ikework:

virtual MyClass& newInstance() const
            {
                  return new TestClass();
            }

this has not yet called by the app, When I debugg I have commented out new TestClass()
And I changed name parameters to a const as
MyClass::MyClass(const String& name) : name(L"TEST")
{
}

And commented out new operator, I see memory detected as
Data: <  T  E S T       > CD 00 44 00 41 00 54 00 45 00 00 00 CD CD CD CD
{52} normal block at 0x00AB1B30, 66 bytes long.

If I have call 5 times it means I use IMPLEMENT_MY_OBJECT 5 times then memory leak for TEST showed 5 time also.

Any ideas again?

Hi
Infinity08,
So you mean we can ignore this? do you have any ideas to help again?

Many thank to all you guys!
0
 
ikeworkCommented:
>> Yes, that's pretty much it.

i guess the "newInstance()" - function is called anywhere in the program, but it is never deleted .. it looks suspicious .. :)
0
 
ikeworkCommented:
sorry didnt see your last post, when writing mine ..
0
 
ikeworkCommented:
>> So you mean we can ignore this? do you have any ideas to help again?

i woulnt .. unless i'm very sure everything is destroyed properly ..

can you put a "printf" in the constructor and destructor of that class, to see if it is destroyed properly:


class Test
{
public:
    Test() { printf"class Test created\n" ); }
    ~Test() { printf"class Test destroyed\n" ); }
};

that'll show, if every created object was destroyed properly ..

0
 
MobinexAuthor Commented:
I have build this in a dll and use in my app,
I am not call _CrtDumpMemoryLeaks, I used BoundCheckers to detect memory leak in VC++6.0

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                               )
{
#ifdef _DEBUG
      switch(ul_reason_for_call)
      {
            case DLL_PROCESS_ATTACH:
                  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
            break;
      }
#endif

      return TRUE;
}
0
 
ikeworkCommented:
ok, then you can log to a logfile


#define LOG_CTOR( className ) { FILE *p = fopen( "log.log", "a" ); fprintf( p, "class %s created\n", (className) ); fclose( p ); }
#define LOG_DTOR( className ) { FILE *p = fopen( "log.log", "a" ); fprintf( p, "class %s destroyed\n", (className) ); fclose( p ); }

class Test
{
public:
    Test() { LOG_CTOR( "Test" ); }
    ~Test() { LOG_DTOR( "Test" ); }
};

0
 
MobinexAuthor Commented:
I have added destructor to MyClass
as below and run with debug, I see memory detected  throw before it call desstructor function
MyClass::~MyClass()
{
 printf("%s\n",name.c_str())
}

I saw name each class printed to console screen after memory infos showed to window debug view

So it means memory checked do before the class destroyed then it is OK?
Any ideas again?
Many thank :-)

class MyClass
{
public:
      MyClass(const String& name);
    ~ MyClass();
      virtual MyClass& newInstance() const;
      const String& toString() const;
      const String& getName() const;
      static const MyClass& forName(const String& className);
protected:
      static void registerClass(const MyClass * myClass);
      String name;
};
MyClass::MyClass(const String& name) : name(name)
{
}
MyClass::~MyClass()
{
 printf("%s\n",name.c_str())

}

0
 
itsmeandnobodyelseCommented:
To add to above information:

First, all static class members which have a string (String) member *will not* be able to free (delete) the memory for the string *before* the final leak check. There is no way out beside you would turn the String to a const char* or a to a const TCHAR*. The latter would only store a pointer to a literal, so it is no leak. The String will allocate memory at the heap, so you have the leak.

The amcro DECLARE_MY_OBJECT  seems to declare a (sub) class 'NewClass' derived from MyClass. MyClass has a String member 'name'. The macro defines a static member 'theNewClass'. Any static class member was globally defined and needs an instantiation. That instantiation was made with the IMPLEMENT_MY_OBJECT macro, e. g.

   TestClass::ClassTestClass TestClass::theClassTestClass;


Here we have the object which 'is a' MyClass object and therefore has a String member 'name' which makes the final leak as static objects were deleted *after* leak-checking.

What you can do:

The MyClass seems to be the baseclass for a class factory. I don't think that it necessarily needs a String member 'name'. If you want to give each 'myObject' a unique id, you might consider to use an integer 'ObjectId' which automatically was incremented with each construction. Or you define a pure virtual function 'getName()' which each derived class has to overload.

You also could consider to omit the static 'theNewClass' object or turn it to a pointer which could be freed in a final 'exit' function *before* the leak manager runs. If you omit the static 'theNewClass' you could run your factory by registering a static 'create function' rather than a static class object. The DECLARE and IMPLMEMENT macros could as well define a static create function as they now create a static class instance.

Summarizing: you have a few choices to get rid of the leak warning. But if you let it as it is, there is nothing wrong as you simply can ignore these messages (which show in debug mode only).

Regards, Alex
0
 
MobinexAuthor Commented:
ok, It is very clearly to me,
Now I will ignore this because it is really a memory leak.

I will change to your suggestion when I have time.

Many thanks again!
0
 
Infinity08Commented:
>> >> Yes, that's pretty much it.
>> 
>> i guess the "newInstance()" - function is called anywhere in the program, but it is never deleted .. it looks suspicious .. :)

Are we still talking about this :

        static ClassTestClass theClassTestClass;

because that's what I was talking about.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Not really an answer to your question as I think that's already been covered quite adequately, but just to add that the default constructor of the std::string class does not offer a no-throw exception guarantee; it is therefore dangerous to define it as a static object. If the constructor throws an exception the application will just crash as there is nothing to catch the exception! It is far safer to use POD (Plain Old Data) types for this: -

std::string const s ("I can throw"; // This might fail for various reasons);
char const sz[] = "I cannot fail!";

Also, if you are writing multi-threaded code remember that making static objects non-const might lead to unchecked race conditions!

I hope these thoughts prove helpful.

-Rx.
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 9
  • 5
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now