What is the C++ Standard specified behavior of new
in c++?
The usual notion is that if new
operator cannot allocate dynamic memory of the requested size, then it should throw an exception of type std::bad_alloc
.
However, something more happens even before a bad_alloc
exception is thrown:
C++03 Section 3.7.4.1.3: says
An allocation function that fails to allocate storage can invoke the currently installed new_handler(18.4.2.2), if any. [Note: A program-supplied allocation function can obtain the address of the currently installed new_handler using the set_new_handler function (18.4.2.3).] If an allocation function declared with an empty exception-specification (15.4), throw(), fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall only indicate failure by throw-ing an exception of class std::bad_alloc (18.4.2.1) or a class derived from std::bad_alloc.
Consider the following code sample:
#include <iostream>
#include <cstdlib>
// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
std::cerr << "Unable to satisfy request for memoryn";
std::abort();
}
int main()
{
//set the new_handler
std::set_new_handler(outOfMemHandler);
//Request huge memory size, that will cause ::operator new to fail
int *pBigDataArray = new int[100000000L];
return 0;
}
In the above example, operator new
(most likely) will be unable to allocate space for 100,000,000 integers, and the function outOfMemHandler()
will be called, and the program will abort after issuing an error message.
As seen here the default behavior of new
operator when unable to fulfill a memory request, is to call the new-handler
function repeatedly until it can find enough memory or there is no more new handlers. In the above example, unless we call std::abort()
, outOfMemHandler()
would be called repeatedly. Therefore, the handler should either ensure that the next allocation succeeds, or register another handler, or register no handler, or not return (i.e. terminate the program). If there is no new handler and the allocation fails, the operator will throw an exception.
What is the new_handler
and set_new_handler
?
new_handler
is a typedef for a pointer to a function that takes and returns nothing, and set_new_handler
is a function that takes and returns a new_handler
.
Something like:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
set_new_handler’s parameter is a pointer to the function operator new
should call if it can’t allocate the requested memory. Its return value is a pointer to the previously registered handler function, or null if there was no previous handler.
How to handle out of memory conditions in C++?
Given the behavior of new
a well designed user program should handle out of memory conditions by providing a proper new_handler
which does one of the following:
Make more memory available: This may allow the next memory allocation attempt inside operator new’s loop to succeed. One way to implement this is to allocate a large block of memory at program start-up, then release it for use in the program the first time the new-handler is invoked.
Install a different new-handler: If the current new-handler can’t make any more memory available, and of there is another new-handler that can, then the current new-handler can install the other new-handler in its place (by calling set_new_handler
). The next time operator new calls the new-handler function, it will get the one most recently installed.
(A variation on this theme is for a new-handler to modify its own behavior, so the next time it’s invoked, it does something different. One way to achieve this is to have the new-handler modify static, namespace-specific, or global data that affects the new-handler’s behavior.)
Uninstall the new-handler: This is done by passing a null pointer to set_new_handler
. With no new-handler installed, operator new
will throw an exception ((convertible to) std::bad_alloc
) when memory allocation is unsuccessful.
Throw an exception convertible to std::bad_alloc
. Such exceptions are not be caught by operator new
, but will propagate to the site originating the request for memory.
Not return: By calling abort
or exit
.
Defined in header |
||
class bad_alloc; |
||
std::bad_alloc
is the type of the object thrown as exceptions by the allocation functions to report failure to allocate storage.
Inheritance diagram
Contents
- 1 Member functions
- 2 std::bad_alloc::bad_alloc
- 2.1 Parameters
- 3 std::bad_alloc::operator=
- 3.1 Parameters
- 3.2 Return value
- 4 std::bad_alloc::what
- 4.1 Parameters
- 4.2 Return value
- 4.3 Notes
- 5 Inherited from std::exception
- 5.1 Member functions
- 5.2 Example
- 5.3 See also
[edit] Member functions
constructs a new bad_alloc object (public member function) |
|
replaces the bad_alloc object (public member function) |
|
returns the explanatory string (public member function) |
std::bad_alloc::bad_alloc
(1) | ||
bad_alloc() throw(); |
(until C++11) | |
bad_alloc() noexcept; |
(since C++11) | |
(2) | ||
bad_alloc( const bad_alloc& other ) throw(); |
(until C++11) | |
bad_alloc( const bad_alloc& other ) noexcept; |
(since C++11) | |
Constructs a new bad_alloc
object with an implementation-defined null-terminated byte string which is accessible through what().
1) Default constructor.
2) Copy constructor. If *this
and other
both have dynamic type std::bad_alloc
then std::strcmp(what(), other.what()) == 0. (since C++11)
Parameters
other | — | another exception object to copy |
std::bad_alloc::operator=
bad_alloc& operator=( const bad_alloc& other ) throw(); |
(until C++11) | |
bad_alloc& operator=( const bad_alloc& other ) noexcept; |
(since C++11) | |
Assigns the contents with those of other. If *this and other both have dynamic type std::bad_alloc
then std::strcmp(what(), other.what()) == 0 after assignment. (since C++11)
Parameters
other | — | another exception object to assign with |
Return value
*this
std::bad_alloc::what
virtual const char* what() const throw(); |
(until C++11) | |
virtual const char* what() const noexcept; |
(since C++11) | |
Returns the explanatory string.
Parameters
(none)
Return value
Pointer to a null-terminated string with explanatory information. The string is suitable for conversion and display as a std::wstring. The pointer is guaranteed to be valid at least until the exception object from which it is obtained is destroyed, or until a non-const member function (e.g. copy assignment operator) on the exception object is called.
Notes
Implementations are allowed but not required to override what()
.
Inherited from std::exception
Member functions
destroys the exception object (virtual public member function of std::exception ) [edit]
|
|
returns an explanatory string (virtual public member function of std::exception ) [edit]
|
[edit] Example
#include <iostream> #include <new> int main() { try { while (true) { new int[100000000ul]; } } catch (const std::bad_alloc& e) { std::cout << "Allocation failed: " << e.what() << 'n'; } }
Possible output:
Allocation failed: std::bad_alloc
[edit] See also
A terminate called after throwing an instance of ‘std::bad_alloc’ is a memory-related error in a programming language C++. What causes the error is a difficult one to track down because it depends on many factors. However, you don’t have any reasons for alarm because we have identified the causes.
Keep on reading, as we’ll teach you what causes this error, and detailed explanations of how to fix them.
Contents
- Why Is Terminate Called After Throwing an Instance of ‘Std::bad_alloc’ Is Happening?
- – Memory Allocation Failure
- – Ram-consuming Tasks in Bedtools
- – Memory Corruption
- How To Fix Termination Error?
- – Use Try-catch Block To Catch the Std::bad_alloc Exception
- – Use New(Std::Nothrow) To Prevent the Exception
- – Subset Large Files When Working in Bedtools
- – Fix Your Code to Avoid the Std::bad_alloc Exception
- Conclusion
A terminate called after throwing an instance of ‘std::bad_alloc’ failure can occur because the reasons listed below:
- Memory allocation failure
- RAM-consuming tasks in Bedtools
- Memory corruption
– Memory Allocation Failure
In your C++ program, when you allocate large chunks of memory with “new”, an error occurs if you run the program. That’s because such allocation leads to an allocation failure. As a result, the code triggers the ‘std::bad_alloc’ exception. This is C++’s way of telling you to have a second look at your code because there is no memory for such allocation.
For example, in the code below, we allocated a large chunk of memory using the new keyword. We wrote a statement that should print the value of the allocation. However, that won’t happen because you’ll get an error message, and the program aborts.
#include <iostream>
using namespace std;
int main(){
// Try to allocate a very huge amount of memory.
// As a result, memory allocation fails.
int *myarray = new int[10000000000000];
// An attempt to print the error results
// in an exception of std::bad_aloc
cout << myarray;
return 0;
}
– Ram-consuming Tasks in Bedtools
If you are running a RAM-consuming task in a genomics analysis tool like bedtools, you can get an error. This particular error is an indication that the task is taking most of your RAM. Because of this, there is no memory for the task continuation. As a result, you cause the std::bad_aloc exception, leading to the termination of your task.
For example, read the following series of events:
- You have two files called FileA and FileB
- FileA is around 18 Megabytes
- FileB is around Eight Gigabytes
- You attempted to intersect them with Bedtools
- You get an error message that a terminate was called after throwing an instance of ‘std::bad_alloc’
These series of events lead to high memory consumption. What’s more, it’s FileB that causes the error due to its large size.
– Memory Corruption
An invalid code can lead to memory corruption, meanwhile, you can be sure that you won’t write invalid C++ code. However, things get funny when your program processes direct input from your user. At a later stage, you use this value with the “new” keyword to allocate memory yet, computation on the input can make the value invalid for the “new” keyword.
But note, computation can lead to memory corruption. That’s because the “new” keyword expects a valid value for memory allocation. So, if the value is not valid, an error occurs down the line. For example, in the next code block, we’ve made the following bad coding decisions:
- We’ve set up a memory allocation that depends on a direct user input
- However, we are trusting the user to enter the correct input for the program to run successfully
- We are using the less than equal operator in a wrong place
- There is memory leakage because we did not delete memory created with the “new” keyword
- We’ve used the input operator the wrong way
Due to the decisions listed above, when you run the code, and you enter zero as an input, you’ll get the exception.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
/**
* This program is faulty in so many ways.
* It’s for demonstration purposes only.
* We have a fixed version later in the article.
*/
char ID[10];
int score[15];
int i;
string user_supplied_ID;
cout<< “Welcome to the program” <<endl;
for (i = 0; i <= 10; i++) {
// Ask the user to enter an ID
cout<< “Please enter an ID:”;
// Read the user input
cin >> user_supplied_ID;
// Try to allocate memory using the user
// supplied ID. Afterward, copy the allocation.
char* temp = new char[user_supplied_ID.size()+1];
user_supplied_ID.copy(temp, user_supplied_ID.size() + 1);
ID[i] = user_supplied_ID[0];
// What’ll happen with these three lines?
temp = new char[user_supplied_ID.size()-2];
user_supplied_ID = user_supplied_ID.substr(2,user_supplied_ID.length());
user_supplied_ID.copy(temp, user_supplied_ID.size() + 1);
score[i] = atoi(temp);
}
cout << endl;
cout << “Name” << ” ” << “Average” << endl;
// Loop through the score array.
// there is an error in the loop. Can you see it?
for (i = 0; i <= 15; i++) {
cout << ID[i] << ” “<< score[i] << endl;
}
return 0;
}
How To Fix Termination Error?
You can fix the termination of your program by taking precautionary actions. Such a precaution includes the use of the try-catch block. The latter applies when using the “new” keyword to allocate memory. What’s more, you can use another variant of the “new” keyword, which is new(std::nothrow).
In addition, when working with large files in bedtools, subset your files into chunks. But don’t forget to write code that prevents memory corruption. Now that you know how to fix the exception, let’s talk about it in detail.
– Use Try-catch Block To Catch the Std::bad_alloc Exception
Since the std::bad_alloc is an exception, you can catch it using the try-catch block. When the exception occurs, you can display a generic error message that has two advantages:
- You can write a generic error message in the catch block.
- The compiler will not display an exception message.
However, you’ll see the generic message only if you’ve defined it in the catch block. In the following code, we’ve made two modifications to our first example in this article. The modifications are:
- We’ve wrapped the memory allocation code in the try block.
- We have a defined generic error message in the catch block.
As a result, when you run the code, an exception occurs. However, you’ll see the generic error message and not the exception message.
#include <iostream>
using namespace std;
int main(){
try {
// Try allocating very huge amount of memory
// using the “new” keyword. So, memory allocation fails.
int *myarray = new int[10000000000000];
// If an exception occurs, you’ll not see the
// “success” message below. Meanwhile, the program transfers
// control to the catch block.
cout<<“There was successful memory allocation”<<endl;
}
catch (const bad_alloc& e) { // catch the std::bad_aloc exception
// Tell the user the allocation failed
cout << “Allocation failed: ” << e.what() << ‘n’;
}
return 0;
}
– Use New(Std::Nothrow) To Prevent the Exception
A combination of the “new” and the std::nothrow constant suppresses an exception when it occurs. That’s because the std::nothrow constant tells “new” not to throw an exception on failure, but it should return a null pointer. Therefore, when an exception occurs in your code, you’ll see no exception message.
Using new(std::nothrow) saves us a few lines of code compared to the try-catch block. However, there is no flexibility in writing a generic error message. So, in the code below, we’ve modified the previous code to use std::nothrow. As a result, when you run the code, you’ll see no error message because it’s suppressed.
#include <iostream>
using namespace std;
int main(){
// Try to allocate a very huge amount of memory.
// However, with the std::nothrow constant, you’ll
// see no error message
int *myarray = new(std::nothrow) int[10000000000000];
// Now, when you print the array, you’ll
// get zero and not an exception message.
cout << myarray;
return 0;
}
– Subset Large Files When Working in Bedtools
In Bedtools, when you are working with large files, you should subset them into small chunks. Afterward, you can work on them separately and then merge the files. By doing this, you’ll be able to work with the small chunks, resulting in less RAM consumption. This will help you to avoid the std::bad_aloc exception.
– Fix Your Code to Avoid the Std::bad_alloc Exception
Fixing your code goes a long way in preventing the std::bad_alloc exception. When we say “fixing”, we mean you should write code that’ll not cause memory issues. That’s because if your code causes a memory issue, it increases the chance of an exception. With that said, let’s revisit the code that we showed earlier.
The following is the code from earlier in the article but we’ve added comments that explain the faults in our code.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
/**
* This program contains talking points
* of our bad coding decisions. Mind you, it still
* contains errors.
*/
char ID[10];
int score[15];
int i;
string user_supplied_ID;
cout<< “Welcome to the program” <<endl;
// OBSERVATION1: In the for loop, we used the
// less than equal (<=) to instead of less than (<) operator.
// As a result, the loop goes out of bounds.
for (i = 0; i <= 10; i++) {
// Ask the user to enter an ID
cout<< “Please enter an ID:”;
// Read the user input
cin >> user_supplied_ID;
// OBSERVATION2: There is no need for the temp string
char* temp = new char[user_supplied_ID.size()+1];
user_supplied_ID.copy(temp, user_supplied_ID.size() + 1);
ID[i] = user_supplied_ID[0];
/**
* OBSERVATION3
* i. If user_supplied_ID.size() is less than 2 char new[] becomes invalid.
ii. If user_supplied_ID.size() is greater than 2 for example 5,
you would allocate tem as only 3 chars without room for the null-terminator.
iii. You would copy 3 chars and the null-terminator into temp. As a result, you can cause memory corruption.
iv. There is memory leakage because we are not deleting
the allocated memory of the “new” operator.
*/
temp = new char[user_supplied_ID.size()-2];
user_supplied_ID = user_supplied_ID.substr(2,user_supplied_ID.length());
user_supplied_ID.copy(temp, user_supplied_ID.size() + 1);
score[i] = atoi(temp);
}
cout << endl;
cout << “Name” << ” ” << “Average” << endl;
// OBSERVATION4: Same as OBSERVATION1
for (i = 0; i <= 15; i++) {
cout << ID[i] << ” “<< score[i] << endl;
}
return 0;
}
Check the following fixed code. In the code, we’ve made significant changes to prevent the std::bad_alloc exception. Our changes include the use of getline() to read the user inputs. In addition, we’ve made adjustments to the for loop and we no longer use std::string.
#include <iostream>
using namespace std;
int main()
{
/**
* This is the fixed version of our program.
* Don’t worry, it does not throw a std::bad_alloc exception!.
* Therefore, run the program, enter zero as an input,
* you’ll get no std::bad_alloc exception.
*/
// Declare the ID and score variables
char ID[15];
int score[15];
cout << “Welcome to the program.nPlease enter 15 different ID numbersn”;
// Contrary to what we did before, we are
// declaring the “i” at the point of usage.
// What’s more, we use the less-than sign
for (int i = 0; i < 15; ++i) {
cout << “Kindly enter an ID:”;
cin >> ID[i];
cin >> score[i];
}
cout << endl;
// Print the IDs and Average values
cout << “Name” << ” ” << “Average” << endl;
// Loop through the score. Also, note that we’ve used
// the less-than sign. This prevents the loop from
// going out of bounds.
for (int i = 0; i < 15; ++i) {
cout << ID[i] << ” ” << score[i] << endl;
}
return 0;
}
Conclusion
This article explained the causes of the std::bad_alloc exception and how you can fix them. So, the following is the summary of our discussion:
- Large memory allocation with the “new” keyword causes the std::bad_alloc exception.
- An attempt to intercept a large file in bedtools can cause the std::bad_alloc exception.
- You can use new(std::nothrow) to prevent the throwing of an exception.
- Good C++ code can prevent the std::bad_alloc exception.
- You can catch the std::bad_exception with a try-catch block.
The std::bad_aloc exception can be a tough one to fix. However, everything that you’ve learned in this article will help you prevent and fix it.
- Author
- Recent Posts
Your Go-To Resource for Learn & Build: CSS,JavaScript,HTML,PHP,C++ and MYSQL. Meet The Team
bad_alloc in C++
Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article
Prerequisite : Exceptions in C++
Standard C++ contains several built-in exception classes. The most commonly used is bad_alloc, which is thrown if an error occurs when attempting to allocate memory with new.
This class is derived from exception.
To make use of bad_alloc, one should set up the appropriate try and catch blocks. Here’s a short example, that shows how it’s used :
#include <iostream>
#include <new>
int
main () {
try
{
int
* gfg_array =
new
int
[100000000];
}
catch
(std::bad_alloc & ba)
{
std::cerr <<
"bad_alloc caught: "
<< ba.what();
}
return
0;
}
RunTime error :
bad_alloc caught: std::bad_alloc
Last Updated :
27 Feb, 2018
Like Article
Save Article
Trusted answers to developer questions
Educative Answers Team
Grokking the Behavioral Interview
Many candidates are rejected or down-leveled in technical interviews due to poor performance in behavioral or cultural fit interviews. Ace your interviews with this free course, where you will practice confidently tackling behavioral interview questions.
Exceptions in C++ are run-time anomalies or abnormal conditions that a program encounters during its execution. C++ provides the following specialized keywords for exception handling:
try
: represents a block of code that can throw an exception.
catch
: represents a block of code that is executed when a particular exception is thrown.
Definition
std::bad_alloc
is a type of exception that occurs when the new operator fails to allocate the requested space. This type of exception is thrown by the standard definitions of operator new
(declaring a variable) and operator new[]
(declaring an array) when they fail to allocate the requested storage space.
Code
The following code displays the error message shown when std::bad_alloc
is thrown.
#include <iostream>
#include <new>
// Driver code
int main () {
try
{
int * myarray = new int[1000000000000];
}
catch (std::bad_alloc & exception)
{
std::cerr << "bad_alloc detected: " << exception.what();
}
return 0;
}
RELATED TAGS
what
std::bad_alloc
exception
c++
Copyright ©2023 Educative, Inc. All rights reserved
Trusted Answers to Developer Questions
Related Tags
what
std::bad_alloc
exception
c++
Learn in-demand tech skills in half the time
Copyright ©2023 Educative, Inc. All rights reserved.
Did you find this helpful?