Freeing Memory

Started by
21 comments, last by Kyn 15 years, 3 months ago
I'm a Beginner/Intermediate level programmer. I'm currently working through 3D Game Engine Design, and I've run across a great many questions about programming technique. The book is currently building a Skin Manager, which will hold Texture and Material Data. The Texture structure is as follows...

typedef struct ZFXTEXTURE_TYPE {
   float     fAlpha;    // overall transparency value
   char     *chName;    // texture filename
   void     *pData;     // texture data
   ZFXCOLOR *pClrKeys;  // color key array
   DWORD     dwNum;     // number of color keys
   } ZFXTEXTURE;

I will be dynamically allocating memory for these lovely textures, it seems. Probably using "malloc" for the chName, pData, and pClrKeys... and probably using "new" for the structure itself, if the following destructor code is any indication. In the destructor for my the Skin Manager, I have to free up this memory. Now here's my question... Is there any point to setting chName, pData, and pClrKeys to NULL when I'm just going to be deleting the Texture object anyway?(I can say object, right? Even though it comes from a structure?)

ZFXD3DSkinManager::~ZFXD3DSkinManager(void) {

   // release direct3d texture objects
   if (m_pTextures) {
      for (UINT i=0; i<m_nNumTextures; i++) {
         if (m_pTextures.pData) {
            ((LPDIRECT3DTEXTURE9)(m_pTextures.pData))->Release();
            m_pTextures.pData = NULL;
            }
         if (m_pTextures.pClrKeys) {
            delete [] m_pTextures.pClrKeys;
            m_pTextures.pClrKeys = NULL;
            }
         if (m_pTextures.chName) {
            delete [] m_pTextures.chName;
            m_pTextures.chName = NULL;
            }
         }
      free(m_pTextures);
      m_pTextures = NULL;
      }
   
   // release allocated memory
   if (m_pMaterials) {
      free(m_pMaterials);
      m_pMaterials = NULL;
      }

   if (m_pSkins) {
      free(m_pSkins);
      m_pSkins = NULL;
      }
   Log("offline (ok)");
   } // destructor


What I'm saying is, can I just leave out these: m_pTextures.pData = NULL; m_pTextures.pClrKeys = NULL; m_pTextures.chName = NULL; Is the author just using them out of force of habit? Is there any reason to include them? Is it somehow sloppy to remove them? Could errors occur if I do? Thanks!
Advertisement
It is certainly good practice to initialize pointers to NULL.

delete can be safely called on NULL pointers, not sure about malloc/free.
For the love of god, please tell me that you've just omitted your error checking code for brevity, and you don't really assume that all those functions succeed.
Quote:
What I'm saying is, can I just leave out these:
m_pTextures.pData = NULL;
m_pTextures.pClrKeys = NULL;
m_pTextures.chName = NULL;

Is the author just using them out of force of habit? Is there any reason to include them? Is it somehow sloppy to remove them? Could errors occur if I do?


Making the variables private and accessing them through Accessor functions sounds better. Any function defined in a class or structure is considered inline so I don't think it would make your application extremely larger. Also by giving them direct access to them like that you're basically forcing them to handle memory management; so, you could do all that within the Accessor functions and make life easier.
Hmm, I'm not certain that either of these responses really addresses my question. Could I have another opinion?

ComboFrog, I'm not currently initializing variables- I'm in a destructor. I'm killing the variables. I also test to see if the pointers are NULL before calling delete/free

And openglJunkie, I'm currently following a book that already has a framework set up for me, and I'm not interested in diverging from it at this time by using accessor functions and the like. And, even if I used them, I'd still have dynamically generated data to free, so my question still stands.

Let me restate my question for clarity:
I'm looking at code that's already been written out in a book, in "3D Game Engine Programming".

I want to know if there's a reason for clearing the 3 pointers I specified to NULL. The pointers have already had their individual data freed. The object that contains these pointers is about to be deleted, and they'll never be accessed again.

I don't think there is any reason to set the pointers to NULL in the destructor because, as you say, they are about to be deleted anyway. You don't have to check for NULL before doing delete or free either according to the standard.
Since you are using C++, why aren't you using C++?

It's usually a poor idea to mix malloc()/free() and new/delete. Even if you operate on entirely different objects with them (which is technically legal), it's needlessly opaque.

Furthermore, you can use more robust types provided by the C++ standard library to alleviate the need for most of your manual memory management anyway, making your code much safer and easier to maintain (chName can be a std::string, pClrKeys a std::vector<ZFXCOLOR>, et cetera).

Finally, "typedef struct..." is a C-ism you don't need in C++.

I realize you're getting this code from a book, but these are still issues to think about since the book is illustrating for you rather poor practices.

And to answer you question directly, you can omit assignments of null to the pointers in the destructor. There is no reason to have them.
Thank you for answering my question jonathanjansson ;) It /felt/ like I didn't need them... but they're neat and it /seems/ like a good habit to NULLify them, just in case something goes horribly wrong.

As for jpetrie, the whole of your post was useless, except for the very last line. Please avoid preaching.

Irregardless, thank you for confirming what jonathanjasson already said. Thank you for taking the time to help, and thank you for taking the time to criticize and try to improve me.

But jpetrie, I'm following a book. I've taken some slight offense to your comment. And if you didn't intend offense, please use 'the author' instead of 'you'. I cannot change the author's code, and when I look at what he's written, I have questions about it. No offense, but I need my questions answered in situ. I can't find a flawless look-alike to ask you about.

Furthermore, I don't really mind whether my code is perfectly OOP or C++. C's a fine language. As long as it's parts are being used for their intended purposes, there's no reason to Soap Box. I like structs for handling small batches of data. Nice and tidy when I don't plan on putting in any functions. Easy to access. Don't have to build any functions- just some simple dot syntax. I use unions, too. And arrays. When appropriate.

I like:

typedef struct ZFXTEXTURE_TYPE {   float     fAlpha;    // overall transparency value   char     *chName;    // texture filename   void     *pData;     // texture data   ZFXCOLOR *pClrKeys;  // color key array   DWORD     dwNum;     // number of color keys   } ZFXTEXTURE;


Much more than I like

class ZFXTEXTURE{private:   float     m_fAlpha;    // overall transparency value   char     *m_chName;    // texture filename   void     *m_pData;     // texture data   ZFXCOLOR *m_pClrKeys;  // color key array   DWORD     m_dwNum;     // number of color keyspublic:   ZFXTEXTURE(float fAlpha, char* chName, void* pData, ZFXCOLOR * pClrKeys, DWORD dwNum);   ~ZFXTEXTURE;   float GetAlpha();   char** GetName();      void** GetData();   ZFXCOLOR** GetColorKeys();   DWORD GetColorKeyNum();   void SetAlpha(float fAlpha);   void SetName(char* chNAme);   void SetData(void* pData);   void SetColor(ZFXCOLOR* pClrKeys);   void SetColorKeyNum(DWORD dwNum);   }ZFXTEXTURE::ZFXTEXTURE(float fAlpha, char* chName, void* pData, ZFXCOLOR * pClrKeys, DWORD dwNum){   m_fAlpha = fAlpha;   m_chName = chName;   m_pData = pData;   m_pClrKeys = pClrKeys;   m_dwNum = dwNum;}ZFXTEXTURE::~ZFXTEXTURE(){         if (m_pTextures.pData) {            ((LPDIRECT3DTEXTURE9)(m_pTextures.pData))->Release();            m_pTextures.pData = NULL;            }         if (m_pTextures.pClrKeys) {            delete [] m_pTextures.pClrKeys;            m_pTextures.pClrKeys = NULL;            }         if (m_pTextures.chName) {            delete [] m_pTextures.chName;            m_pTextures.chName = NULL;            }      }float ZFXTEXTURE::GetAlpha(){   return m_fAlpha;}char** ZFXTEXTURE::GetName()  {   return &m_chName;} void** ZFXTEXTURE::GetData(){   //Cause the point was /not/ to copy my texture data. Double Pointer   //Could also pass one through the parameters   return &m_pData;}ZFXCOLOR** ZFXTEXTURE::GetColorKeys(){   return &m_pClrKeys;}DWORD ZFXTEXTURE::GetColorKeyNum(){   return m_dwNum;}void ZFXTEXTURE::SetAlpha(float fAlpha){   m_fAlpha = fAlpha;}void ZFXTEXTURE::SetName(char* chNAme){   m_chName = m_chName;}void ZFXTEXTURE::SetData(void* pData){   m_pData = pData;}void ZFXTEXTURE::SetColor(ZFXCOLOR* pClrKeys){   m_pClrKeys = pClrKeys;}void ZFXTEXTURE::SetColorKeyNum(DWORD dwNum){   m_dwNum = dwNum;}


Oh hell, do I like that better. The second is just redundant. Structures have a place and a purpose, and so do classes.

[Edited by - Kyn on January 9, 2009 9:10:59 PM]
Quote:
As for jpetrie, the whole of your post was useless, except for the very last line. Please avoid preaching.

And if you don't want unsolicited advice, please avoid making posts on a public forum asking for help. Your original question was answered quite effectively already, so frankly I see no fault in pointing out ways in which you could improve yourself as a programmer. That is, in fact, why I moderate this forum.

If you're not interested in suggestions on how to improve your code you are entirely free to ignore them. As fair warning, the remainder of this post will be a comment on the educational process. You may want to skip it.

Quote:
But jpetrie, I'm following a book. You're criticizing my coding practices... when I'm not the one coding.

It is through critique and peer review that we learn. You shouldn't make the mistake of taking critique of your code as critique of your person, nor you should you read that critique as any kind of lack of respect of your person on the part of the person offering the critique. You seem awefully offended that somebody is just trying to help.

Furthermore, I'm quite aware that you're getting the code from a book and thus it is not code of your complete authorship. That doesn't make it any more or less than what it is, however, and what it is is poor C++ code. It is not idiomatic within the language, nor is it promoting safe, efficient, manageable practices. The value you place on those -- the latter, especially -- directly correlates to the value you place on the professionalism of this craft.

Quote:
Secondly, I don't really mind whether my code is perfectly OOP or C++. C's a fine language.

Nothing I mentioned really had anything to do with OO as a paradigm; I don't mind whether your code is OO or not either. There is a time and place for everything, and if the paradigm isn't appropriate or desired there is nothing wrong with not using it.

C is a fine language, too. But C is C and C++ is C++. You are using one or the other. In this case, you are using C++ since you are using at least "new," "delete" and "class" and such -- all of these are C++-only constructs.

You make a fine point about both being used for their intended purposes, but you're not using C here. You are using the idioms of C within C++, and they are very different languages that just so happen to share enough syntactical compatibility as to be backwards compatible. But C++ isn't a strict superset of C in terms of functionality and behavior. You can write seriously broken programs by misusing C idioms in C++, because much of the behavioral differences are very subtle. Fortunately nothing you've shown here is anywhere near that kind of danger, but the damage done still runs the gamut from stylistically poor (but subjective) and objectively unsafe (such as the use of manual memory management where RAII via std::vector and such would be a better option and thus -- as I mentioned -- something you should think about).

Quote:
like structs for handling small batches of data. Nice and tidy when I don't plan on putting in any functions. Easy to access. Don't have to build any functions- just some simple dot syntax. I use unions, too. And arrays. When appropriate.

...

Oh hell, do I like that better. The second is just redundant. Structures have a place and a purpose, and so do classes.

You misunderstood me greatly. At no point did I suggest to you that you replace the former code with the latter, there. In fact, you are correct in disliking the latter code, because it is redundant and a pointless "encapsulation" of data -- a bad design.

I suggested you avoid "typedef struct..." because that is a C-ism. In C++, you can simply use "struct..." without the typedef. As such, what I was suggesting there was:
struct ZFXTEXTURE{   float     fAlpha;    // overall transparency value   char     *chName;    // texture filename   void     *pData;     // texture data   ZFXCOLOR *pClrKeys;  // color key array   DWORD     dwNum;     // number of color keys   };

Not that class you seemed to think I was suggesting. That class exhibits very poor encapsulation design among other things.

Additionally, some of what you are saying sounds to me like you think struct and class are different things in C++. They are not, in general. In fact, they differ only in that a struct's members (and inheritance access) are public by default, and a class's are private by default. In all other respects you can interchange struct and class as much as you want.
Jpetrie.

Thank you for clarifying! Your second post was /exceptionally/ useful!

I'm quite sorry for seeming irate- I was only mildly disgruntled. I take this moment to X out my comment about you preaching. Just let me establish that I wrote none of this code and had no hand in it whatsoever- it was written by a man named Stefan Zerbst. Credit/Critique him, not me.

I get the sense that he is oldschool and used to doing things the 'C' way. I also feel that he's uncomfortable with several of the sections he wrote. That's okay with me- I'll survive. But I'll keep in mind what you wrote- after all, the last thing I want to do is learn everything /wrong/.

Would you further clarify some of the things you said?

I was always under the impression that typdef was necessary in order to reference the structure without including the ugly 'struct' modifier before every use of the structure. I did a lot of research and that's what I'd come up with.

Would you please explain this to me, and where my confusion lies?

Sorry for my little tangent about changing the struct to a class. One of the posters above you suggested I use accessor functions, and I think I was trying to hit two birds with one stone. I know that structs and classes are very similar. But um, I thought class fields were by default protected, not private?

Can you use "new" with basic types, like 'int'?

Allow me to defend the use of arrays, and tell me if I'm getting anything wrong.

Vectors aren't a replacement for arrays, as far as I understand- they're a powered-up variant of arrays. Like classes are to structs. Sometimes I just want four numbers, neatly cataloged. I don't want any added functionality, no expansion/contraction, none of that. When I know I don't want to change my array size, the added bonuses of vectors become moot. There's a little more overhead, more work, and it's not really worth it.

*Char's, I can't really defend ;) Strings! Strings all the way, I tell you! Char arrays are only useful if they aren't meant to be strings!

Again, Thank you, and my apologies for how my post came off.
Quote:Can you use "new" with basic types, like 'int'?

Yes, it's C++. You can do anything you want in C++. Even the terrible things.

Quote:Vectors aren't a replacement for arrays, as far as I understand- they're a powered-up variant of arrays. Like classes are to structs. Sometimes I just want four numbers, neatly cataloged. I don't want any added functionality, no expansion/contraction, none of that. When I know I don't want to change my array size, the added bonuses of vectors become moot. There's a little more overhead, more work, and it's not really worth it.

This is probably why there exists boost::array. Gonna reiterate that in C++, a struct is a class with default public access. Classes are in no way 'powered-up'.

This topic is closed to new replies.

Advertisement