Ada sebuah metode yang disebut foo
yang kadang-kadang menghasilkan galat berikut:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abort
Apakah ada cara bahwa saya dapat menggunakan coba-coba
-menangkap
blok untuk menghentikan kesalahan ini mengakhiri program saya (semua saya ingin lakukan adalah kembali -1
)?
Jika demikian, apa yang merupakan sintaks untuk itu?
Bagaimana lagi yang bisa saya berurusan dengan bad_alloc
di C++?
Secara umum anda tidak, dan tidak harus mencoba, untuk menanggapi kesalahan ini. bad_alloc
menunjukkan bahwa sumber daya yang tidak dapat dialokasikan karena tidak tersedia cukup memori. Dalam kebanyakan skenario program anda tidak bisa berharap untuk mengatasi dengan itu, dan mengakhiri segera adalah satu-satunya yang berarti perilaku.
Lebih buruk lagi, sistem operasi modern sering di-alokasikan: pada sistem seperti ini, malloc
dan baru
dapat berlaku pointer bahkan jika tidak ada cukup memori yang tersisa – std::bad_alloc
tidak akan pernah dilempar, atau setidaknya bukan tanda yang dapat diandalkan dari memori kelelahan. Sebaliknya, upaya untuk akses memori yang dialokasikan maka akan mengakibatkan kesalahan segmentasi, yang tidak catchable (anda dapat handle segmentasi sinyal kesalahan, tetapi anda tidak dapat melanjutkan program sesudahnya).
Satu-satunya hal yang anda bisa lakukan ketika catching std::bad_alloc
adalah mungkin log kesalahan, dan mencoba untuk memastikan aman program penghentian dengan membebaskan sumber daya yang luar biasa (tapi ini dilakukan secara otomatis dalam kegiatan normal dari tumpukan unwinding setelah kesalahan akan dilemparkan jika program menggunakan RAII tepat).
Dalam kasus-kasus tertentu program dapat mencoba untuk membebaskan beberapa memori dan coba lagi, atau menggunakan memori sekunder (= disk), bukan dari RAM tetapi peluang tersebut hanya ada dalam skenario yang sangat spesifik dengan kondisi yang ketat:
Ini sangat jarang bahwa aplikasi memiliki kontrol atas point 1 — login sistem aplikasi tidak pernah melakukan, itu adalah sistem pengaturan yang memerlukan izin root untuk mengubah.1
OK, jadi mari kita asumsikan anda sudah fixed point 1. Apa yang sekarang dapat anda lakukan adalah misalnya menggunakan LRU cache untuk beberapa data anda (mungkin beberapa sangat besar bisnis benda-benda yang dapat diregenerasi atau reloaded on demand). Selanjutnya, anda perlu untuk menempatkan sebenarnya logika yang mungkin gagal menjadi fungsi yang mendukung retry — dengan kata lain, jika itu akan dibatalkan, anda hanya dapat peluncuran ini:
``
lru_cache
double perform_operation(int widget_id) {
std::opsional
...
for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) { try { kembali perform_operation(widget_id); } catch (std::bad_alloc const&) { jika (widget_cache.kosong()) throw; // error di tempat lain. widget_cache.remove_oldest(); } }
// Menangani terlalu banyak usaha yang gagal di sini. ``
Namun bahkan di sini, menggunakan std::set_new_handler
bukan penanganan std::bad_alloc
memberikan manfaat yang sama dan akan menjadi jauh lebih sederhana.
1 Jika anda membuat sebuah aplikasi yang tidak control point 1, dan anda sedang membaca jawaban ini, silahkan menembak saya email, saya benar-benar ingin tahu tentang keadaan anda.
baru
di c++?Gagasan biasa adalah bahwa jika baru
operator tidak dapat mengalokasikan memori dinamis dari ukuran yang diminta, maka harus melempar pengecualian dari jenis std::bad_alloc
.
Namun, sesuatu terjadi bahkan sebelum bad_alloc
pengecualian dilemparkan:
C++03 Bagian 3.7.4.1.3: kata
Sebuah fungsi alokasi yang gagal untuk mengalokasikan penyimpanan yang bisa memohon saat ini diinstal new_handler(18.4.2.2), jika ada. [Catatan: program yang disediakan alokasi fungsi dapat mendapatkan alamat saat ini diinstal new_handler menggunakan set_new_handler fungsi (18.4.2.3).] Jika alokasi fungsi dinyatakan dengan kosong pengecualian-spesifikasi (15.4), membuang(), gagal untuk mengalokasikan penyimpanan, itu akan mengembalikan suatu null pointer. Lainnya fungsi alokasi yang gagal untuk mengalokasikan penyimpanan hanya akan menunjukkan kegagalan membuang-ing pengecualian dari kelas std::bad_alloc (18.4.2.1) atau kelas yang berasal dari std::bad_alloc.
Perhatikan contoh kode berikut:
#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 memory\n";
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;
}
Dalam contoh di atas, operator baru
(kemungkinan besar) tidak akan dapat mengalokasikan ruang untuk 100,000,000 bilangan bulat, dan fungsi outOfMemHandler()
akan disebut, dan program akan membatalkan setelah mengeluarkan pesan kesalahan.
Seperti yang terlihat di sini perilaku default baru
operator ketika tidak mampu memenuhi memori permintaan, adalah untuk memanggil baru-handler
function berulang-ulang sampai ia dapat menemukan memori yang cukup atau tidak ada lagi penanganan baru. Dalam contoh di atas, kecuali kita sebut std::abort()
, outOfMemHandler()
akan disebut berulang kali. Oleh karena itu, pawang harus memastikan bahwa alokasi berhasil, atau daftarkan lain handler, atau daftarkan no handler, atau tidak kembali (yaitu menghentikan program). Jika tidak ada handler baru dan alokasi gagal, operator akan melempar pengecualian.
new_handler
dan set_new_handler
?new_handler
adalah typedef untuk pointer ke fungsi yang mengambil dan mengembalikan apa-apa, dan set_new_handler
adalah fungsi yang mengambil dan mengembalikan new_handler
.
Sesuatu seperti:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
set_new_handler's parameter pointer ke fungsi operator baru
harus menelepon jika itu dapat't mengalokasikan memori yang diminta. Nilai kembali adalah pointer ke sebelumnya terdaftar fungsi handler, atau null jika tidak ada sebelumnya handler.
Mengingat perilaku baru ' a dirancang dengan baik pengguna program harus menangani keluar dari kondisi memori dengan menyediakan tepat
new_handler'which tidak salah satu dari berikut:
Membuat lebih banyak memori yang tersedia: hal Ini dapat memungkinkan berikutnya alokasi memori upaya dalam operator baru's loop untuk berhasil. Salah satu cara untuk melaksanakan hal ini adalah untuk mengalokasikan blok besar memori pada program start-up, kemudian lepaskan untuk digunakan dalam program ini pertama kalinya baru-handler ini dipanggil.
Pasang baru yang berbeda-handler: Jika baru saat ini-handler bisa't membuat lebih banyak memori yang tersedia, dan dari sana baru-handler yang bisa, maka baru saat ini-handler dapat menginstal lainnya baru-handler di tempatnya (dengan menyebut set_new_handler
). Waktu berikutnya operator panggilan baru baru-fungsi handler, akan mendapatkan salah satu yang paling baru-baru ini diinstal.
(Sebuah variasi pada tema ini adalah untuk yang baru-handler untuk mengubah perilaku sendiri, jadi pada saat itu's dipanggil, itu sesuatu yang berbeda. Salah satu cara untuk mencapai ini adalah untuk memiliki baru-handler memodifikasi statis, namespace tertentu, atau data global yang mempengaruhi baru-handler's perilaku.)
Uninstall baru-handler: hal Ini dilakukan dengan melewati null pointer ke set_new_handler
. Dengan tidak baru-handler diinstal, operator
baru akan melempar pengecualian ((convertible untuk) std::bad_alloc
) ketika alokasi memori tidak berhasil.
Exception convertible untuk std::bad_alloc
. Pengecualian tersebut tidak akan tertangkap oleh operator baru
, tapi akan merambat ke situs yang berasal permintaan untuk memori.
Tidak kembali: Dengan memanggil batalkan
atau keluar
.
Anda dapat menangkap hal itu seperti yang lain kecuali:
try {
foo();
}
catch (const std::bad_alloc&) {
return -1;
}
Cukup apa yang anda dapat berguna lakukan dari titik ini adalah terserah anda, tapi itu's pasti layak secara teknis.
Saya tidak akan menyarankan hal ini, karena bad_alloc
berarti anda memori. Itu akan menjadi yang terbaik untuk menyerah, bukannya mencoba untuk pulih. Namun berikut ini adalah solusi yang anda minta:
try {
foo();
} catch ( const std::bad_alloc& e ) {
return -1;
}
Boleh saya sarankan lebih sederhana (dan lebih cepat) solusi untuk ini. baru
operator akan mengembalikan null jika memori tidak dapat dialokasikan.
int fv() {
T* p = new (std::nothrow) T[1000000];
if (!p) return -1;
do_something(p);
delete p;
return 0;
}
Saya berharap ini bisa membantu!
Biarkan anda foo program exit dengan cara yang terkontrol:
#include <stdlib.h> /* exit, EXIT_FAILURE */
try {
foo();
} catch (const std::bad_alloc&) {
exit(EXIT_FAILURE);
}
Kemudian menulis program shell yang memanggil program yang sebenarnya. Karena ruang alamat yang terpisah, keadaan program shell selalu didefinisikan dengan baik.