• Advertisement
Sign in to follow this  

Dynamic Memory and throwing Exceptions

This topic is 1054 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm looking for some guidance when it comes to allocating dynamic memory and throwing exceptions.
 
So lets say I have a situation where I need to create some dynamic memory based on a value returned by a function
 
int size = GetSomeSize();
int *buffer = new int[size];
 
Now lets say I need to use this buffer variable later on in the program.
Where I pass it to a function that has the ability to purposely throw a run time error. In addition this function does not attempt to catch the runtime error.
 
So we are looking at something like:
 
int size = GetSomeSize();
int *buffer = new int[size];
BufferManip(buffer);
 
What happens if:
 
1. The function (BufferManip) fails? What happens to the dynamic memory if an outside function catches the runtime error thrown?
2. What happens if the function catches the runtime error? What happens to the dynamic memory allocated?
3. What is the best way to handle situation where you need dynamic memory and you know an exception can be thrown? Edited by noodleBowl

Share this post


Link to post
Share on other sites
Advertisement

1. The function fails? What happens to the dynamic memory if an outside function catches the runtime error thrown?

Assuming you mean BufferManip throws an exception, the answer is it depends on the calling code.
 
Let's say you have this code
 
int size = GetSomeSize();
int *buffer = new int[size];
BufferManip(buffer);
delete buffer;
if BufferManip throws an exception then delete buffer won't be called and you have a memory leak. 
 
you could fix this by catching the exception.
int size = GetSomeSize();
int *buffer = new int[size];
try
{
  BufferManip(buffer);
}
catch (...)
{
   delete buffer;
}

2. What happens if the function catches the runtime error? What happens to the dynamic memory allocated?

If BufferManip swallows the exception (i.e. it doesn't propagate up the stack), then buffer can be deleted.

3. What is the best way to handle situation where you need dynamic memory and you know an exception can be thrown?

Don't use a raw pointer. Use a vector.

Bear in mind that the new operator can throw an exception if it can't allocate the requested memory.

Also, most games don't use exceptions. Edited by ChaosEngine

Share this post


Link to post
Share on other sites


you could fix this by catching the exception.

int size = GetSomeSize();
int *buffer = new int[size];
try
{
BufferManip(buffer);
}
catch (...)
{
delete buffer;
}

...and now the delete is not called in the common case when no exception is thrown. If there was an exception its silently discarded.

Because its so easy to make a mistake with this you should really avoid using new and delete manually. You could use a vector or unique_ptr instead to have this problem handled automatically.

Edited by wintertime

Share this post


Link to post
Share on other sites

Also, most games don't use exceptions.


Then what do games do? Are you implying that games just crash?
Or are you saying they don't purposely toss errors?
 

Because its so easy to make a mistake with this you should really avoid using new and delete manually. You could use a vector or unique_ptr instead to have this problem handled automatically.


Is a unique_ptr the same as a smart pointer?

I guess more specifically I'm talking something like this:
int main()
{
	try
	{
		MyObject a;
		ManipObject(a);
	
	}
	catch (std::runtime_error &e)
	{
		std::cout << e.what() << std::endl;
	}

}

void ManipObject(MyObject &a)
{
	int size = GetSomeSize();
	int *buffer = new int[size];
	
	//Can throw exception
	BufferManip(a, buffer);
	
	delete [] buffer;
}

void BufferManip(MyObject &a, int *buffer)
{
	//Just some example codes
	if(a.var == 0)
		buffer[0] = 1;
	else if(a.var == 1)
		buffer[0] = 2;
	else
		throw std::runtime_error("Invalid MyObject val!");		
}

In this case buffer never gets cleaned up if an exception is thrown. But since the program then would end do I really have a mem leak?
If I never have the try catch, the program would then just crash so is it better not to handle it?

What about only handling it for logging purposes? I basically just want the try catch there because it will let me know where my program
failed when I run it outside the compiler

Since we are on the top of dynamic memory
What happens if I do something like this?


int *buffer = new int[1024];
BufferManip(a, buffer);

buffer = new int[2048];
BufferManip(a, buffer);
delete [] buffer;

Should I be deleting before I do the second new? Or does it not matter? Edited by noodleBowl

Share this post


Link to post
Share on other sites


Is a unique_ptr the same as a smart pointer?

A unique_ptr is more like the old auto_ptr. It specifies exactly one owner, whereas smart_ptr specifies an unknown number of owners.

 

That makes unique_ptr extremely lightweight, and is explicitly designed to solve this issue. You should, 99% of the time, be using std::vector to manage memory buffers, with std::unique_ptr to fill the remaining cases.

Share this post


Link to post
Share on other sites

...and now the delete is not called in the common case when no exception is thrown. If there was an exception its silently discarded.
Because its so easy to make a mistake with this you should really avoid using new and delete manually. You could use a vector or unique_ptr instead to have this problem handled automatically.


HA! The funny thing is, the whole point of my post was to point out that you shouldn't use raw pointers without a very good reason. I wrote that code without thinking and I screwed it up... and people wonder why best practice is to use vectors biggrin.png
 

Then what do games do? Are you implying that games just crash?
Or are you saying they don't purposely toss errors?


I saying that many games will disable exceptions in their C++ compiler, and use some other error handling mechanism.

Historically exception support in console C++ compilers has been pretty bad. Not sure if that's improved with the current generation.

What happens if I do something like this?

int *buffer = new int[1024];
BufferManip(a, buffer);

buffer = new int[2048];
BufferManip(a, buffer);
delete [] buffer;
 Should I be deleting before I do the second new? Or does it not matter?

 

You shouldn't do that. You are allocation 4k bytes somewhere in memory. Then you throw away the address of those 4k bytes, so you can't tell the OS you're finished with that memory.
 
What does that mean in practice? For this example, on a modern OS, on a machine from this century? Almost nothing. You lose 4k of memory and then the OS will clean it up when you exit the program.
 
But it's a bad habit to get into. If that was a bigger chunk of memory, or that was in some code called in a loop, it could become a problem.

 

 

Seriously, just use a vector. It will make your life so much easier. 

Share this post


Link to post
Share on other sites

whereas smart_ptr specifies an unknown number of owners.

 

What's smart_ptr? Do you mean shared_ptr?

 

 

To the O.P.: As others have said, use vector. Possibly unique_ptr<int[]> is another option, if the semantics of unique_ptr fit your usage scenario.

 

Also, this is essential reading if you are allocating memory or acquiring any unmanaged resources (file handles, critical sections, etc...) in an environment where exceptions can be thrown:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

Edited by phil_t

Share this post


Link to post
Share on other sites

Maybe worth recalling somebody isn't AAA. Exceptions are extremely handy and considering the first few posts of this thread are clearly written by someone who doesn't have an accurate view of what's going on, I'd suggest to stick to what C++ suggests to do as canon as long as there isn't a specific product to talk about.

Share this post


Link to post
Share on other sites

Here's a good game developer's view on the matter:
http://bitsquid.blogspot.com.au/2012/01/sensible-error-handling-part-1.html
 
Personally, even though they're not really a performance concern any more, I still choose to avoid them in C++ because writing exception-safe C++ code is hard. As in, still hard for someone who's been practicing C++ for a decade. I use them in C#/Java/Python/etc though...
Also, designing code in such a way that errors aren't a thing you have to deal with is the first priority.


I agree with a lot with what this blog post has to say, but at the same time the one part where they go over:
 
Exceptions
Rather than crashing isn’t it better to throw an exception? If the exception isn’t caught we get a crash, just as before. But we also have the option, if we really want to, to catch the exception and handle the error. It would seem that by using exceptions we can have our cake and eat it too.

I do and I don't agree with this part.
Let's say I have the following:
 

TypeObject CreateType(int value)
{
     TypeObject a;
     switch(value)
     {
         case 1:
         a.type = 1;
         break;
 
         case 2:
         a.type = 2;
         break;
 
         case 3:
         a.type = 3;
         break;
 
         default:
         throw std::runtime_error("Failed to create object. Unknown type: " + value);
         break;
     }
 
     return a;
} 

The first thought that I have is "If I don't know what the type is force the program to crash". Then have:

int main()
{   try
    {
       TypeObject obj = CreateType(4);
    }
    catch(exception &e)
    {
       //Logging of e.what() to file
    }
}

To catch the exception for logging. I mean is this a bad idea?

What happens if I do the above catch and I run into a access violation? Will it still get caught since its just a base exception I'm looking for?

 

 

Maybe worth recalling somebody isn't AAA. Exceptions are extremely handy and considering the first few posts of this thread are clearly written by someone who doesn't have an accurate view of what's going on, I'd suggest to stick to what C++ suggests to do as canon as long as there isn't a specific product to talk about.

I mean this guy is right. When it comes to exceptions I'm not sure what I should be doing.

I mean the idea behind "crashing" is bad to me, only because I have trouble figuring out why and where (I'm talking about outside the debugger here) the crash happened

Share this post


Link to post
Share on other sites

Here's a good game developer's view on the matter:
http://bitsquid.blogspot.com.au/2012/01/sensible-error-handling-part-1.html
 
Personally, even though they're not really a performance concern any more, I still choose to avoid them in C++ because writing exception-safe C++ code is hard. As in, still hard for someone who's been practicing C++ for a decade. I use them in C#/Java/Python/etc though...
Also, designing code in such a way that errors aren't a thing you have to deal with is the first priority.


I agree with a lot with what this blog post has to say, but at the same time the one part where they go over:
 
Exceptions
Rather than crashing isn’t it better to throw an exception? If the exception isn’t caught we get a crash, just as before. But we also have the option, if we really want to, to catch the exception and handle the error. It would seem that by using exceptions we can have our cake and eat it too.

I do and I don't agree with this part.
Let's say I have the following:
 

TypeObject CreateType(int value)
{
     TypeObject a;
     switch(value)
     {
         case 1:
         a.type = 1;
         break;
 
         case 2:
         a.type = 2;
         break;
 
         case 3:
         a.type = 3;
         break;
 
         default:
         throw std::runtime_error("Failed to create object. Unknown type: " + value);
         break;
     }
 
     return a;
} 
The first thought that I have is "If I don't know what the type is force the program to crash". Then have:

int main()
{   try
    {
       TypeObject obj = CreateType(4);
    }
    catch(exception &e)
    {
       //Logging of e.what() to file
    }
}
To catch the exception for logging. I mean is this a bad idea?
What happens if I do the above catch and I run into a access violation? Will it still get caught since its just a base exception I'm looking for?
 
 

Maybe worth recalling somebody isn't AAA. Exceptions are extremely handy and considering the first few posts of this thread are clearly written by someone who doesn't have an accurate view of what's going on, I'd suggest to stick to what C++ suggests to do as canon as long as there isn't a specific product to talk about.

I mean this guy is right. When it comes to exceptions I'm not sure what I should be doing.
I mean the idea behind "crashing" is bad to me, only because I have trouble figuring out why and where (I'm talking about outside the debugger here) the crash happened


Two misconceptions here.

First - exceptions are not "force code to crash". Exceptions are "something happened I can't handle, but my caller might, so tell them". Your example of an invalid type is a good one - you can't decide what you want to do if an invalid type is passed, so you pass the responsibility to the caller. Part of this is making sure you pass enough information to the caller so they know what happened - and not just throwing a generic "runtime error".

Second - the caller should only handle exceptions they can actually do anything about, and let the rest fall through. If you do not expect an exception, don't catch it. Don't catch exceptions you can't handle, and don't write (...) blocks. The exception, of course, is when you're writing code that needs to know an exception happened to clean up resources, like if you were writing std::vector yourself. Though even then you trap the exception, clean up, and then re-throw so the caller can handle it.

Crashing is not a bad thing for the developer. Crashes/unhandled exceptions can be caught by the debugger at the throw site so they can figure out what's wrong. Crashing for the end user is usually not pretty - but it's generally better then corrupting memory and pretending nothing bad happened. Most professional software these days has a top-level crash handler that will catch exceptions and crashes, perform a memory dump, and allow the user to submit a bug report. (You don't need exceptions to do that though, in Windows, a Structured Exception Handler will be enough) Edited by SmkViper

Share this post


Link to post
Share on other sites

Don't catch exceptions you can't handle, and don't write (...) blocks


What is a (...) block?
 

Most professional software these days has a top-level crash handler that will catch exceptions and crashes, perform a memory dump, and allow the user to submit a bug report. (You don't need exceptions to do that though, in Windows, a Structured Exception Handler will be enough)


From what I understand, isn't this just like a Structured Exception Handler?
 

int main()
{   try
    {
       /*All of my other code*/

       TypeObject obj = CreateType(4);

       /* Some other code in my main funciton */
    }
    catch(exception &e)
    {
       //Logging of e.what() to file
    }
}

Share this post


Link to post
Share on other sites

Don't catch exceptions you can't handle, and don't write (...) blocks


What is a (...) block?


Sorry - it's where the exception specification is an ellipsis and doesn't specify the type. It will catch everything that is thrown, not just things that inherit from some exception class.

try
{
  throw 1; // this won't be caught
}
catch(std::exception& ex)
{
  std::cout << "Caught something!";
}

try
{
  throw 1; // this now will be caught
}
catch(...)
{
  std::cout << "Caught something!";
}
It's usually frowned upon because there is rarely anything you can do to recover from such a catch block, because you don't know what kind of exception is thrown. The - heh - exception being something that is managing resources and so doesn't care what is thrown, but needs to clean up if anything is thrown.

It's also useful if you're calling a function that can throw in an destructor to prevent the exception from escaping the destructor (which is a big no-no in C++)

Most professional software these days has a top-level crash handler that will catch exceptions and crashes, perform a memory dump, and allow the user to submit a bug report. (You don't need exceptions to do that though, in Windows, a Structured Exception Handler will be enough)


From what I understand, isn't this just like a Structured Exception Handler?
 

int main()
{   try
    {
       /*All of my other code*/

       TypeObject obj = CreateType(4);

       /* Some other code in my main funciton */
    }
    catch(exception &e)
    {
       //Logging of e.what() to file
    }
}

No, that only catches C++ exceptions - and only things that inherits from the "exception" class at that.

If you dereferenced a null pointer, it wouldn't be caught, because that doesn't fire a C++ exception.

Structured Exception Handling (SEH) involves using "__try" and "__except" (at least in Microsoft's compiler) and doesn't even require C++. You can also set up an unhandled exception filter which a lot of software uses to make dumps to be reported to the developer, as mentioned above.

Note that structured exceptions do NOT clean up the stack like C++ exceptions do (it doesn't have the information to do so, after all). In general they are harder to use, so I would recommend sticking with C++ exceptions and only using SEH for dump creation/error reporting.

Share this post


Link to post
Share on other sites


I mean the idea behind "crashing" is bad to me, only because I have trouble figuring out why and where (I'm talking about outside the debugger here) the crash happened

That's easily resolved. 

 

It takes only a few minutes to configure your application to write a mini dump when it crashes.

 

Then you need to get into a habit of preserving all the source code and intermediate build files for whatever you release. (The first is likely in version control, the second can be kept in a build server.) 

 

With all of that combined you can take a crash report and open all the source in the debugger, frozen at the instant of the crash. Usually (but not always) that is all you need to hunt down the problem. 

Share this post


Link to post
Share on other sites

Structured Exception Handling (SEH) involves using "__try" and "__except" (at least in Microsoft's compiler) and doesn't even require C++. You can also set up an unhandled exception filter which a lot of software uses to make dumps to be reported to the developer, as mentioned above.

Note that structured exceptions do NOT clean up the stack like C++ exceptions do (it doesn't have the information to do so, after all). In general they are harder to use, so I would recommend sticking with C++ exceptions and only using SEH for dump creation/error reporting.

 
Is SEH not meant to be used by code that requires or has objects? (Kind of seems ridiculous if that is the case)
I get an error saying "Cannot use __try in functions that require object unwinding"
 

That's easily resolved. 
 
It takes only a few minutes to configure your application to write a mini dump when it crashes.
 
Then you need to get into a habit of preserving all the source code and intermediate build files for whatever you release. (The first is likely in version control, the second can be kept in a build server.) 
 
With all of that combined you can take a crash report and open all the source in the debugger, frozen at the instant of the crash. Usually (but not always) that is all you need to hunt down the problem.


This may seem stupid, but are there alternatives to writing a minidump through window's api?

Share this post


Link to post
Share on other sites

std::unique_ptr and std::shared_ptr are both 'smart pointers', just to be clear. They serve similar purposes, but are used in different circumstances.
 

This may seem stupid, but are there alternatives to writing a minidump through window's api?

 
Write better logging output, possibly use custom asserts.

Currently my stack-traces aren't working (I'm using a third-party library, and I think I configured it wrong - MinGW doesn't make this easy), but I output as much 'automated' details as I can, and also provide more contextual details when asserting. Currently I output to .html files with some embedded CSS. It's all really sloppy and duck-taped together, but provides a good first-approximation at figuring out what problem occurred.

Here's some example output:
[spoiler]4e7e13bb82.png[/spoiler]
All the data except the last three lines are auto-generated using information provided either by the compiler, or by myself in other parts of the code.
 
Once the work is done behind the scenes and wrapped up neatly (or less-than-neatly, in my case), the higher-level code to output that is as simple as:

Log::Message(MSG_SOURCE("ConfigFile", Log::Severity::Error))
    << "Previously failed to load a config file, and it was auto-generated. The config file hasn't been updated since the auto-generation.\n"
    << "Confile file: '" << Log_HighlightCyan(GetFilenameFromPath(filepath)) << "'\n"
    << "Path: " << Log_DisplayPath(filepath) << Log::FlushStream;

 
That one just outputs a message, it doesn't crash (because it's not a critical error). If I want to crash, I do this:

Assert(SerializeFromFile(this->Details.TextureDetails, filepath), "Failed to load the 'TextureDetails' resource file.");

Which checks that the statement is true (in this case, that the function returned true returned true), or else it outputs the message using the same logging system, and then crashes with a pop-up box being displayed to the user.
 
In a previous post, I've given some examples of what data you might want to output (you'll have to scroll down to the bottom of the post, as most of it is unrelated).
ApochPIQ describes the benefits of embedding a tiny web server in your code. Others have done this as well.
Others talk about how to provide more context for your errors (I'm using this in my screenshot above, among other things).

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

Structured Exception Handling (SEH) involves using "__try" and "__except" (at least in Microsoft's compiler) and doesn't even require C++. You can also set up an unhandled exception filter which a lot of software uses to make dumps to be reported to the developer, as mentioned above.

Note that structured exceptions do NOT clean up the stack like C++ exceptions do (it doesn't have the information to do so, after all). In general they are harder to use, so I would recommend sticking with C++ exceptions and only using SEH for dump creation/error reporting.

 
Is SEH not meant to be used by code that requires or has objects? (Kind of seems ridiculous if that is the case)
I get an error saying "Cannot use __try in functions that require object unwinding"


Yes, that is a restriction, but only for the function actually containing the __try/__except. A usual solution is to write a main-function which contains nothing but the SEH around a call to another function (for example safeMain) which contains everything you would normally put into main.

Share this post


Link to post
Share on other sites
Yeah I only have a single __try in the whole engine, internally the crash dump code.

Also, one of the reasons that you should try to make invalid code crash is so you don't need crash dumps :D

If the code crashes very reliably and predictably, a programmer can easily reproduce a bug while their own debugger is attached by following the steps provided by the bug reporter.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement