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
.
Сообщение от Avazart
логичнее убивать сам сценарий
Что значит “сам сценарий”? Сценарий тоже выполняется каким-то кодом. Если сценарий, например, завис, значит и код, который его исполняет тоже завис. Если этот код находится в том же процессе, что и вся остальная машинерия браузера – это проблема.
Сообщение от Avazart
или поток
Это довольно сложно сделать корректно. В некоторых случаях невозможно. После принудительного завершения потока, в котором исполнялся ошибочный или слишком требовательный к ресурсам код, приводящий к зависанию, в некорректном состоянии может остаться непредсказуемое число ресурсов программы, которые прямо или косвенно с этим потоком разделялись. В этом случае после завершения потока программа будет находиться в состоянии UB. Единственное, что можно сделать с этим – завершить остальной процесс.
Кроме того, как я уже говорил, когда все вкладки браузера находятся в одном адресном пространстве гораздо проще получить несанкционированный доступ к данным. В одном вкладке открыт какой-нибудь онлайн банк, а в соседней сайт злоумышленника, со зловредным скриптом, который ворует данные первой вкладки. Гипотетически сделать это проще, потому что все данные в одном адресном пространстве.
Так что, мультипроцессная организация – это самое логичное, что можно придумать для повышения стабильности работы современного браузера.
Прежде чем возражать мне дальше, советую прочитать также это: https://blog.chromium.org/2008… cture.html
Добавлено через 7 минут
Сообщение от Avazart
Не давай полномочий и не нужно будет думать о защите.
К сожалению в программах бывают ошибки. Этими ошибками могут воспользоваться злоумышленники.
В современном браузере очень много программного кода, в том числе стороннего – flash контент, java-апплеты, javascript, расширения и т.д. Каждый такой код – потенциальная уязвимость. Лучше и проще сделать архитектуру так, чтобы она сразу отсекала большинство опасных ситуаций.
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
I wrote the code pasted below to perform the following tasks in the order in which they are stated:
- Read an input file and count the number of entries in it
- Create an array of appropriate size (size equal to number of entries)
- Go back to the beginning of the input file and read it again
- Store the entries in an array
- Print out the number of entries in the file and the entries themselves.
Here is my code:
#include <iostream>
#include <fstream>
#include <exception>
using namespace std;
int main(int argc, char* argv[]){
ifstream inFile(argv[1]); //passing arguments to the main function
int numEntries;
if(!inFile){
cout << "file not found" << endl;
return 1;
}
string entry;
while (!inFile.eof()){ //counting the number of entries
getline(inFile,entry);
++numEntries;
}
const int length = numEntries; //making an array of appropriate length
int*arr = new int[length];
inFile.clear(); //going back to the beginning of the file
inFile.seekg(0, ios::beg);
int i = 0;
const int size = numEntries; //making an array to store the entries in the file
int matrix[size];
int pos = 0;
int variable = 0;
while(pos < size){
inFile >> variable;
matrix[pos] = variable;
++pos;
}
cout<< numEntries << "entries have been read"<< endl;
inFile.close();
for(int i = 0; i < pos; ++i)
cout << matrix[i] << endl; //printing out the entries
return 0;
}
When I execute the .cpp file I keep getting the error message:
terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped)
I have gathered this has to do with a memory shortage or variables falling out of the main() function, but I can not figure out how to address the problem in this specific situation. If it is relevant, I am working on a Linux computer.
asked Oct 8, 2016 at 18:21
6
This code has 3 holes:
First hole: int numEntries
. Later you do: ++numEntries;
You increment unspecified value. Not sure if it’s UB, but still bad.
Second and third hole:
const int length = numEntries;
int* arr = new int[length];
And
const int size = numEntries;
int matrix[size];
numEntries
has unspecified value (first hole). You use it to initialize length
and size
– that is Undefined Behaviour. But let’s assume it is just some big number – you allocate memory of unspecified size (possibly just very big size), hence the std::bad_alloc
exception – it means you want to allocate more memory that you have available.
Also, matrix
is VLA
of unspecified size, which is both non-standard and Undefined behaviour.
answered Oct 8, 2016 at 18:38
xinaizxinaiz
7,6846 gold badges34 silver badges77 bronze badges
0
Loss of focus, wasted 30 mins:
class Cls1{
int nV; // <------------- nV is un-initialized
vector<bool> v1;
public:
Cls1 () {
v1 = vector<bool> (nV + 1, false); // <------------------ nV is used
}
};
As you can see nV is un-initialized, but is used below in constructor.
Since the nV took garbage value, different for each run, the program sometimes worked, and other times crashed when the nV garbage value is very high (garbage value)
-
Rextester didn’t crash, possibly due to some different initialization, https://rextester.com/l/cpp_online_compiler_gcc
-
Apache Netbeans does not show this as warning
- Having files under Git, you can see changes easily, will find these issue.
Hope that helps.
answered Apr 11, 2019 at 0:03
Какое стандартное поведение С++ указано в new
в С++?
Обычное понятие состоит в том, что если оператор new
не может выделять динамическую память запрошенного размера, тогда он должен выдать исключение типа std::bad_alloc
.
Тем не менее, что-то еще происходит еще до того, как выбрано исключение bad_alloc
:
С++ 03 Раздел 3.7.4.1.3: говорит
Функция распределения, которая не может выделить хранилище, может вызывать установленный в настоящий момент new_handler (18.4.2.2), если таковой имеется. [Примечание. Функция распределения, предоставленная программой, может получить адрес текущего установленного пользователя new_handler с помощью функции set_new_handler (18.4.2.3).] Если функция распределения, объявленная с пустой спецификацией исключения (15.4), throw(), не может выделить хранилище, он должен вернуть нулевой указатель. Любая другая функция распределения, которая не может выделить хранилище, должна указывать только на отказ путем выброса исключения класса std:: bad_alloc (18.4.2.1) или класса, полученного из std:: bad_alloc.
Рассмотрим следующий пример кода:
#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;
}
В приведенном выше примере operator new
(скорее всего) не сможет выделить место для 100 000 000 целых чисел, и будет вызвана функция outOfMemHandler()
, и программа будет отменена после выдача сообщения об ошибке
Как показано здесь, поведение оператора new
по умолчанию, когда он не может выполнить запрос на память, заключается в вызове функции new-handler
, пока он не сможет найти достаточное количество памяти или новых обработчиков. В приведенном выше примере, если мы не назовем std::abort()
, outOfMemHandler()
будет вызываться повторно. Поэтому обработчик должен либо гарантировать, что следующее распределение будет успешным, либо зарегистрировать другой обработчик, либо не зарегистрировать обработчик, либо не вернуть (т.е. Завершить программу). Если нового обработчика нет, и выделение не выполняется, оператор выдает исключение.
Что такое new_handler
и set_new_handler
?
new_handler
является typedef для указателя на функцию, которая принимает и ничего не возвращает, а set_new_handler
– это функция, которая принимает и возвращает new_handler
.
Что-то вроде:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
set_new_handler – указатель на оператор функции new
должен вызывать, если он не может выделить запрошенную память. Его возвращаемое значение является указателем на ранее зарегистрированную функцию обработчика или null, если предыдущий обработчик не был.
Как справиться с условиями памяти в С++?
Учитывая поведение new
, хорошо спроектированная пользовательская программа должна обрабатывать из памяти условия, предоставляя правильный new_handler
, который выполняет одно из следующих действий:
Сделать доступной память:. Это может привести к успешной попытке следующей попытки выделения памяти внутри нового цикла оператора. Один из способов реализовать это – выделить большой блок памяти при запуске программы, а затем выпустить его для использования в программе при первом вызове new-обработчика.
Установить новый новый обработчик:. Если текущий новый обработчик не может сделать больше доступной памяти, и есть другой новый обработчик, который может, то текущий новый обработчик может установите другой новый обработчик на свое место (вызывая set_new_handler
). В следующий раз оператор new вызовет функцию нового обработчика, он получит тот, который был установлен последним.
(Вариант этой темы – для нового обработчика, чтобы изменить его собственное поведение, поэтому в следующий раз, когда он вызывается, он делает что-то другое. Один из способов добиться этого – заставить new-handler изменить статический, специфические или глобальные данные, которые влияют на поведение нового обработчика.)
Удалить новый обработчик: Это делается путем передачи нулевого указателя на set_new_handler
. Если новый обработчик не установлен, operator new
выдаст исключение ((конвертируется в) std::bad_alloc
), когда распределение памяти не будет выполнено.
Отбросить исключение, конвертируемое в std::bad_alloc
. Такие исключения не попадают на operator new
, но будут распространяться на сайт, отправляющий запрос на память.
Не вернуть:. Вызовите abort
или exit
.