Thread: Question regarding Memory Leak

  1. #16
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    One question after following the discussion:
    How would you handle code which might throw an exception without try/catch?
    For example take any call to new or something. Thank you.

  2. #17
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    you could use new(nothrow) to call new and not return an exception. Maybe somebody else can fill you in on the details.

  3. #18
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    but then I need to test for NULL?
    But it really was just an example. On most calls to new I have no influence, lets say if the stl calls new internally. Or just lets assume "precompiled code which just can potentially raise an exception"

  4. #19
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    What do you mean by "handle"?

    I would ensure that my code doesn't leak resources using RAII. Often, I can use some smart processing to provide even better exception guarantees. Sometimes, I can't. Then I use catch-all and rethrow.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #20
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    A concrete example converting a string to an int:

    Code:
            string s("ab");
            int i = -1;
            try {
                i = lexical_cast<int>(s);
            }
            catch(const bad_lexical_cast&) {
                  // reject input
            }
    could somebody show me how to transform this peace of code so it doesn't use try/catch but is still able to reject wrong input while keeping the process running?

  6. #21
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You could not use lexical_cast.

    But you're completely missing brewbuck's point.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #22
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Yes, probably. Not like it's an uncommon feeling for me... :/

  8. #23
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Quote Originally Posted by pheres View Post
    One question after following the discussion:
    How would you handle code which might throw an exception without try/catch?
    For example take any call to new or something. Thank you.
    You'd have a try/catch, but elsewhere in the code, you don't need to pepper your constructors and such with them to avoid memory leaks if you use a smart pointer class of some kind.

    Assume you had this:

    A* a = new A;
    B* b = new B;
    C* c = new C;
    D* d = new D;

    Now assume C's constructor throws. That means you leak the memory that was successfully allocated in A and B. And if D's constructor throws, you leak the memory from A, B, and C.

    If you use a smart pointer, you can get around all of this:

    std::auto_ptr<A> a(new A);
    std::auto_ptr<B> b(new B);
    std::auto_ptr<C> c(new C);
    std::auto_ptr<D> d(new D);

    Now, if "new C" throws, stack unwinding will cause a and b's destructors to be called, which will free the memory allocated by "new A" and "new B". No leaks now.

    If you wrap every dumb pointer in a smart pointer at the moment you create it, you'll get rid of memory leak possibilities.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  9. #24
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Hunter2 View Post
    Why don't we all just kiss and make up?
    I'm not upset.

    Assignment operators etc. are excellent ways to deal with "the issues they are designed to address".
    Yes, they are. However, it is possible to ELIMINATE "the issues they are designed to address," therefore eliminating THEIR use.

    If you choose to interpret their intended purpose as implementing these high-level primitives you speak of (smart pointers etc.), so be it. I believe Bubba's comment was more in response to your "Never use X!" tone than anything else; so, let's just leave this argument at "absolute statements are frowned upon on this forum."
    Obviously it's impossible to NEVER use an assignment operator or copy constructor. These are necessary to implement what I'm talking about.

    I think Bubba is just mad at me for some comments I made about C# and Microsoft the other day

  10. #25
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by pheres View Post
    A concrete example converting a string to an int:

    Code:
            string s("ab");
            int i = -1;
            try {
                i = lexical_cast<int>(s);
            }
            catch(const bad_lexical_cast&) {
                  // reject input
            }
    could somebody show me how to transform this peace of code so it doesn't use try/catch but is still able to reject wrong input while keeping the process running?
    Yes. Remove the try/catch. Now the exception can propagate out to a more appropriate catching point.

    Obviously exceptions have to be caught somewhere. But this should be dictated by general architecture, NOT just because you need to clean up after yourself. If you find yourself needing a try/catch in order to prevent a resource leak, then you can almost always find a better way to do the same thing without the try/catch.

  11. #26
    Registered User
    Join Date
    Sep 2007
    Location
    Arizona
    Posts
    164
    I have read all the posts and I think that things have become a little confused as the thread grew. Here is some background on the original post:

    This is an online data structures class where I have the book to read and an obviously non-responsive instructor. My resources for the class are the textbook and you all (and google to a lesser degree).

    The textbook is: Data Structures using C++ by D. S. Malik. The question references the material covered in Chapter 3, Pointers and Array-Based Lists (Chapter One covered: Software Engineering Principles and C++ Classes, while Chapter Two covered: Object-Oriented Design(OOD) and C++). Chapter three sections prior to the quote below are Pointer Data Types and Pointer Variables; Dynamic Variables; Dynamic Arrays; Functions and Pointers; Shallow versus Deep Copy and Pointers; and now for the current section:
    “Classes and Pointers: Some Peculiarities.
    If a pointer variable is of a class type, we discussed, in the previous section, how to access class members via the pointer by using the arrow notation. Because a class can have pointer data members, this section describes some peculiarities of such classes. To facilitate the discussion, we use the following class:
    Code:
    	class pointerDataClass
    {
    public:
    		…
    private:
    		int x;
    		int lenP;
    		int *p;
    };
    Also consider the following statements:
    pointerDataClass objectOne;
    pointerDataClass objectTwo;

    Destructor.
    The object objectOne has a pointer data member p. Suppose that during program execution the pointer p creates a dynamic array. When objectOne goes out of scope, all data members of objectOne are destroyed. However p created a dynamic array, and dynamic memory must be deallocated using the operator delete. Therefore, if the pointer p does not use the delete operator to deallocate the dynamic array, the memory space of the dynamic array would stay marked as allocated, even though no one can access it. This is known as a ‘memory leak.’ How do we ensure that when p is destroyed, the dynamic memory created by p is also destroyed? Suppose that objectOne is as shown in fig3-16. (p points to an array outside the object loaded with integers {5, 36, 24, 15, …}
    Recall that if a class has a destructor, the destructor automatically executes whenever a class object goes out of scope. Therefore, we can put the necessary code in the destructor to ensure that when objectOne goes out of scope, the memory created by the pointer p is deallocated. This is one of the main purposes of including a destructor. For example, the definition of the destructor for the class pointerDataClass is:
    Code:
    	PointerDataClass::~pointerDataClass()
                 {
    	      delete [] p;
                  }
    Of course, you must include the destructor as a member of the class in its definition. Let us extend the definition of the class pointerDataClass by including the destructor. Moreover, the remainder of this section assumes that the definition of the destructor is as given previously – that is, the destructor deallocates the memory space pointed to by p.
    Code:
    	class pointerDataClass
    	{
    	public:
    		~pointerDataClass();
    		…
    	private:
    		int x;
    		int lenP;
    		int *p;
    	};
    NOTE: for the destructor to work properly, the pointer p must have a valid value. If p is not properly initialized (that is, if the value of p is garbage) and the destructor executes, either the program terminates with an error message or the destructor deallocates an unrelated memory space. For this reason, you should exercise caution while working with pointer.

    Assignment Operator:
    This section describes the limitations of the built-in assignment operators for classes with pointer data members. Suppose that objectOne and objectTwo are as shown in fig 3-17. (objectOne.x = 8, objectOne.lenP = 50, and objectOne.p points to an array of integers {5, 36, 24, 15, …} while objectTwo.x, objectTwo.lenP, and objectTwo.p are empty) Recall that one of the built-in operations on classes is the assignment operator. For example the statement:
    objectTwo = objectOne;
    copies the data members of objectOne into objectTwo. That is, the value of objectOne.x is copied into objectTwo.x, the value of objectOne.lenP is copied into objectTwo.lenP, and the value of objectOne.p is copied into objectTwo.p. Because p is a pointer, this member-wise copying of data would lead to a shallow copying of the data. That is, both objectTwo.p and objectOne.p would point to the same memory space, as shown in fig 3-18. (you all know what the picture looks like objectOne.p and objectTwo.p point to the same array) Now, if objectTwo.p deallocates the memory space to which it points, objectOne.p would become invalid. This situation could very well happen, if class pointerDataClass has a destructor that deallocates the memory space pointes to by p when an object of the type pointerDataClass goes out of scope. It suggests that there must be a way to avoid this pitfall. To avoid this shallow copying of data for classes with a pointer data member, C++ allows the programmer to extend the definition of the assignment operator. This process is called overloading the assignment operator. Once the assignment operator is properly overloaded, both the objects objectOne and objectTwo have their own data, as shown in fig 3-19. (again, you all know what the picture looks like – objectOne.p points to an array and objectTwo.p points to an array different than objectOne.p bet they are identical)”
    The next section is, Overloading the Assignment Operator (describes how to overload the assignment operator).

    SO, that is the information delivered on the topic in my one resource, and what I used to answer the question of this post as well as formulate my challenge to the test question.

    What I understand from the above quote out of the book is:
    With the shallow copy both pointers point to the same array so when one object goes out of scope, the memory allocated for the array is deallocated resulting in the second object pointer pointing to nothing. This is a problem, but the memory leak is the issue. The memory used by the array is available because it has been deallocated when one of the object pointers went out of scope. The assignment operator overload makes sure the two pointers each point to their own array (with their own allocated memory) so they don’t have to be concerned with what happens to the other object pointer.

    If I have things wrong please correct me, I don't mind getting one wuestion wrong, if I am wrong. But based on what I read, I don't see where a memory leak is prevented with an overloaded assignment operator included int eh class.

    Thanks for all the posts I have been educated.

  12. #27
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Quote Originally Posted by clegs View Post
    If I have things wrong please correct me, I don't mind getting one wuestion wrong, if I am wrong. But based on what I read, I don't see where a memory leak is prevented with an overloaded assignment operator included int eh class.
    If you have objects A and B of the same type in this scenario and both A.ptr and B.ptr point to separate memory blocks, consider what happens if you do A = B;

    Here's what you have first:

    Code:
    A.ptr ---------> Block A
    B.ptr ---------> Block B
    Now after A = B, the shallow copy is done, and this occurs:

    Code:
                           Block A
    A.ptr -------------v 
    B.ptr ---------> Block B
    See the problem? Block A could be lost in the shallow copy.

    An overloaded assignment operator could be used to deallocate the memory of A.ptr before the assignment is done.

    However, as others have mentioned, this is NOT true for all cases, and this is why many of us voted for false (and CornedBee voted true but only because he said he felt he knew the intent of the question). If objects of this type are not responsible for the memory that their member pointers point to, then they should definitely NOT deallocate memory that isn't in their jurisdiction, at least if other parts of the program are relying on that memory to stay alive during assignments.

    To compare it to this example, if Block A needs to stay alive and is controlled by another object, then for A to delete it in the assignment would result in accessing a null pointer, and that could just be plain wrong.

  13. #28
    Registered User
    Join Date
    Sep 2007
    Location
    Arizona
    Posts
    164
    Thanks MacGyver.
    I understand your example. That makes sense. I wish there was an example in the book like that. What I read in the book, which was the only information source I had - there wasn't an example of the pointers pointing to their own list before the copy - deep or shallow. They only had two pointers one pointing to an array and the other just declared. There wasn't any explanation of the example you gave where a pointer was already pointing to a list then the assignment happens for a copy (shallow or otherwise, right?) resulting in a memory leak when they were discussing destructors, assignments operator and memory leaks.

    I just reviewed the section that described how to overload the assignment operator which is the next section after what I posted above. They go into great detail on how to avoid a self copy and what code needs to be present to prevent this. And at the end they give a working example. The code block for the assignment operator in this example has two lines of code:
    if(list != NULL) //Line 2
    destroyList(); //Line 3
    list is a member and otherList is an const reference argument. The explanation following the example states: "The statement in line 2 checks whether list is nonempty. If it is nonempty, then list is destroyed by deallocating the memory occupied by list. ... If otherList is not NULL and not empty, the statements between line 6 and 10 (which I didn't include) create an array list and copy otherList into list." So, I guess that is what this question is referring to.
    I guess I will let this question go without challenge.

    Thanks for your explanation!

  14. #29
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You'll probably want to AddRef the object, though.
    Nope. Only if you create a new device per pointer which is not what is happening. It is a simple assignment which means that since it is a dumb COM pointer some dummy could go and release it which would nullify every object's pointer to the device. But there is still only 1 device and therefore 1 ref count as it relates to my app.

    COM doesn't like it when you attempt to create copies of it's interface pointers. You can have multiple pointers pointing to the interface pointer but you cannot have multiple copies of the interface pointer. COM objects must be instantiated by using CoCreateInstance() or CoCreateInstanceEx(). Any other method (besides wrappers around those methods) will result in an abysmal failure.
    Last edited by VirtualAce; 12-07-2007 at 01:02 AM.

  15. #30
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Bubba View Post
    Nope. Only if you create a new device per pointer which is not what is happening.
    COM objects are reference counted. Calling AddRef doesn't create a copy. It says that the new object may keep the pointer indefinitely.
    It is a COM programming best practice that everything that stores a pointer to a COM object should increase the object's reference count, and decrease it (using Release()) when done with the object.
    Now, in the case of the 3d device you can get away with not doing that, since its life time is probably guaranteed to exceed pretty much everything else, but with other objects, that's not so good.

    COM doesn't like it when you attempt to create copies of it's interface pointers. You can have multiple pointers pointing to the interface pointer but you cannot have multiple copies of the interface pointer.
    You lost me there. If you use "interface pointer" as "a pointer to a COM object", then you're completely wrong. Of course you can have multiple pointers to the same object - that's what the reference counting mechanism is for.
    It's true that you can't just shallow-copy COM objects. But then, you can't ever shallow-copy anything pointed to by a base pointer in C++ by dereferencing the pointer and assigning to something. I can think of three different problems with that off the top of my head.

    COM objects must be instantiated by using CoCreateInstance() or CoCreateInstanceEx(). Any other method (besides wrappers around those methods) will result in an abysmal failure.
    Also not true. You use CoCreateInstance(Ex) when you want to create an object by CLSID. If you actually know the implementing type, you can just use new to create the object, or you can use any other method you can think of. As long as the object's reference count is initialized correctly and the allocation mechanism matches the deallocation it uses for self-deletion, there's nothing wrong with that.
    In fact, in the end every COM object is created in such a way. Don't forget what CoCreateInstance really does (in the case of in-process server DLLs - out-of-process is considerably more complicated; also, the protection mechanism of IClassFactory2 is ignored):
    1) Look up the CLSID in the registry.
    2) Load the DLL listed there.
    3) Load the symbol "DllGetClassObject" from the DLL.
    4) Call this function, passing the CLSID and an IClassFactory**. The function must instantiate the class factory that supports the CLSID and assign to the factory pointer.
    5) Call the class factory's CreateInstance method, passing the IID, the CLSID, and the void** given to CoCreateInstance. The method must instantiate the object that corresponds to the CLSID, initialize it, QueryInterface it to the IID and assign it to the out pointer.

    As you see, CoCreateInstance only delegates to a user-written function for the actual creation anyway. But there's no need to go through this hassle if all you want is to create a COM object you control for someone else to use. For example, I highly doubt that IDirect3D9::CreateDevice uses CoCreateInstance.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Assignment Operator, Memory and Scope
    By SevenThunders in forum C++ Programming
    Replies: 47
    Last Post: 03-31-2008, 06:22 AM
  2. Memory Leak Help
    By (TNT) in forum Windows Programming
    Replies: 3
    Last Post: 06-19-2006, 11:22 AM
  3. Memory Leak
    By Berticus in forum C++ Programming
    Replies: 5
    Last Post: 07-20-2005, 05:11 PM
  4. Memory Address of Array Question
    By Zeusbwr in forum C++ Programming
    Replies: 3
    Last Post: 10-24-2004, 09:58 AM
  5. Is it necessary to write a specific memory manager ?
    By Morglum in forum Game Programming
    Replies: 18
    Last Post: 07-01-2002, 01:41 PM