Я программист C, изучающий С++. В C существует общая goto
идиома, используемая для обработки ошибок и выхода из функции. Я прочитал, что обработка исключений с помощью блоков try
- catch
предпочтительнее в объектно-ориентированных программах, но мне трудно реализовать эту парадигму в С++.
Возьмем, например, следующую функцию в C, которая использует парадигму обработки ошибок goto
:
unsigned foobar(void){
FILE *fp = fopen("blah.txt", "r");
if(!fp){
goto exit_fopen;
}
/* the blackbox function performs various
* operations on, and otherwise modifies,
* the state of external data structures */
if(blackbox()){
goto exit_blackbox;
}
const size_t NUM_DATUM = 42;
unsigned long *data = malloc(NUM_DATUM*sizeof(*data));
if(!data){
goto exit_data;
}
for(size_t i = 0; i < NUM_DATUM; i++){
char buffer[256] = "";
if(!fgets(buffer, sizeof(buffer), fp)){
goto exit_read;
}
data[i] = strtoul(buffer, NULL, 0);
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
printf("%lu\n", data[i] + data[i + NUM_DATUM/2]);
}
free(data)
/* the undo_blackbox function reverts the
* changes made by the blackbox function */
undo_blackbox();
fclose(fp);
return 0;
exit_read:
free(data);
exit_data:
undo_blackbox();
exit_blackbox:
fclose(fp);
exit_fopen:
return 1;
}
Я попытался воссоздать функцию в С++ с помощью парадигмы обработки исключений как таковой:
unsigned foobar(){
ifstream fp ("blah.txt");
if(!fp.is_open()){
return 1;
}
try{
// the blackbox function performs various
// operations on, and otherwise modifies,
// the state of external data structures
blackbox();
}catch(...){
fp.close();
return 1;
}
const size_t NUM_DATUM = 42;
unsigned long *data;
try{
data = new unsigned long [NUM_DATUM];
}catch(...){
// the undo_blackbox function reverts the
// changes made by the blackbox function
undo_blackbox();
fp.close();
return 1;
}
for(size_t i = 0; i < NUM_DATUM; i++){
string buffer;
if(!getline(fp, buffer)){
delete[] data;
undo_blackbox();
fp.close();
return 1;
}
stringstream(buffer) >> data[i];
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
cout << data[i] + data[i + NUM_DATUM/2] << endl;
}
delete[] data;
undo_blackbox();
fp.close();
return 0;
}
Я чувствую, что моя версия на С++ неправильно реализовала парадигму обработки исключений; на самом деле, версия С++ кажется еще менее читаемой и более подверженной ошибкам из-за сборки кода очистки, накапливающегося в блоках catch
по мере увеличения функции.
Я прочитал, что весь этот код очистки в блоках catch может быть ненужным в С++ из-за чего-то RAII, но я не знаком с этой концепцией. Является ли моя реализация правильной, или есть лучший способ обработки ошибок и чистое выключение функции на С++?