Skip to main content

a silhouette of a person's head and shoulders, used as a default avatar

__gnu_cxx и __verbose_terminate_handler

Отвлечемся от std. Рассмотрим пространство имен __gnu_cxx, в котором объявлен __verbose_terminate_handler, позволяющий получить больше информации о возникающей исключительной ситуации. Замечу, что это все тот же заголовочный файл exception.
Рассмотрим следующий код:

int main (int argc, char * const argv[]) {
std::cout << "Hello, World!\n";
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
int k=120;
if(k>100)
throw std::exception();
else
throw k;
for(int i=k;i<1000;++i)
std::cout<<".";
return 0;
}

На выходе получаем следующее:

[Session started at 2008-11-17 23:42:53 +0300.]
Hello, World!
terminate called after throwing an instance of 'std::exception'
what(): St9exception

Как видно из примера, при возникновении исключительной ситуации выводится дополнительная информация о ней, что в некоторых случаях может быть полезным.
a silhouette of a person's head and shoulders, used as a default avatar

Использование set_terminate

Решил немного написать по поводу set_terminate.
Функция set_terminate объявлена в заголовочном файле exception. Она имеет следующий вид:

terminate_handler set_terminate(terminate_handler) throw().

В качестве параметра функция берет указатель на функцию, которая будет вызвана в случае терминирования программы.
Данный указатель на функцию имеет следующий вид:

void (* pF)(void).

Если мы через функцию set_terminate устанавливаем новый обработчик, то она вернет нам старый, если ранее такой существовал для данной ситуации.
Возникает вопрос: а зачем нужно использовать set_terminate? В ответ можно сказать только следующее, что при ошибке в программе, которая ведет к терминированию этой программы, может возникнуть необходимость сохранить данные, закрыть файлы, записать в лог информацию о причинах ошибки и т.д.
В заключении привожу пример использования:

#include <iostream>
#include <exception>

void func1()
{
std::cout<<"The end"<<std::endl;
}

int main (int argc, char * const argv[]) {
std::cout<< "Hello, World!\n";
std::set_terminate(func1);
throw std::exception();
return 0;
}

В результате работы программы получаем следующее:

[Session started at 2008-11-17 23:10:04 +0300.]
Hello, World!
The end

a silhouette of a person's head and shoulders, used as a default avatar

Книга по С++, которую я прочитал первой

Нашел я и книгу, которую прочитал первой при изучении языка С++. Она мне нравилась простотой и последовательностью изложения. Ее удобно использовать, изучая язык. Мне это в ней и нравилось. В настоящее время я, к сожалению, ее уже не имею в своем распоряжении, чтобы подробнее описать. Причина отсутствия: "подарил школьной библиотеке". Так что в школе, где я учился и работал, стало на одну книгу по С++ больше. "Отличный язык в широкие массы!!!".
А вот и ссылка на книгу:
Язык Си++
В. В. Подбельский

Язык Си++
a silhouette of a person's head and shoulders, used as a default avatar

Книга по С++

На вопрос: "Какую книгу почитать по С++?", я предлагаю прочитать книгу Бьерна Страуструпа. Книга интересная, глубокая. Можно прочитать ее поверхностно, выяснив только те вопросы, которые Вас интересуют, а можно копнуть глубоко, прочитав "от корки до корки". Использовать ее как справочник мне очень нравится. Четкое изложение, наличие примера - все что надо для "прояснения вопроса".

Язык программирования С++
Бьерн Страуструп

Язык программирования С++. Специальное издание


Эту книгу я прочитал не первой, однако, купив ее, пользуюсь постоянно.
a silhouette of a person's head and shoulders, used as a default avatar

Перегрузка операторов перенаправления из потока и в поток

Когда мы используем вывод на консоль, то часто пишем следующий код:
std::cout<<"Hello, world"<<std::endl

Предположим, что мы создали класс следующего вида:
class TestClass{
public:
TestClass();
~TestClass();
private:
int i;
std::string s;
};

Для вывода содержимого класса на экран можно воспользоваться созданным специально для этого методом:
class TestClass{
public:
TestClass();
~TestClass();
void output(); // метод для вывода на консоль
private:
int i;
std::string s;
};

void TestClass::output(){
std::cout<<"i="<<i<<"s="<<s<<std::endl;
}

Тогда вывод для экземпляра будет выглядеть так:
TestClass tc;
tc.output();

Такой вариант возможен, но он очень уж некрасив. Переопределим оператор перенаправления в поток, что позволит нам перенаправлять содержимое экземпляра класса в поток вывода:
TestClass tc;
std::cout<<tc<<std::endl;

Для этого реализуем друга класса следующего вида:
class TestClass{
public:
TestClass();
~TestClass();
friend std::ostream& operator<<(std::ostream& out, const TestClass& c);
private:
int i;
std::string s;
};
std::ostream& operator<<(std::ostream& out, const TestClass& c);

Что содержится в теле данного оператора? В нем должен быть реализован функционал по перенаправлению полей класса в поток вывода, например:
std::ostream& operator<<(std::ostream& out, const TestClass& c)
{
out<<"i="<<c.i;
out<<" s="<<c.s;
return out;
}
Т.к. оператор является другом класса, то он имеет доступ к приватным полям класса, что не требует от нас делать их публичными.

Теперь, используя написанный код, можно выводить содержимое класса на консоль:

TestClass tc;
std::cout<<tc<<std::endl;
TestClass *p=new TestClass();
std::cout<<"second: "<<*p<<std::endl;

a silhouette of a person's head and shoulders, used as a default avatar

Еще одна книга

Читать на русском хорошо. Но читать техническую литературу на английском приходится чаще. Можно попрактиковаться при чтении стандарта языка С на английском языке. Соответствующая ссылка приведена ниже:
The C Standard
Standards Institute British
The C Standard : Incorporating Technical Corrigendum 1

Если успеете запастись данной книгой на выходные, то поделитесь своими впечатлениями на тему "Мои английские выходные".
a silhouette of a person's head and shoulders, used as a default avatar

Интересная книга

Хочется поделиться еще одной интересной книгой, которая в настоящий момент доступна для чтения:

C Primer Plus

Стивен Прата

Язык программирования C. Лекции и упражнения


В данной книге очень хорошо и подробно рассмотрен язык. Уделено внимание рассмотрению конкретных примеров. В принципе, эта книга может быть интересно разноуровневым специалистам. Написана известным человеком в данной области. Так что книга "на выходные" есть.
a silhouette of a person's head and shoulders, used as a default avatar

Использование функции _Exit

Рассмотрим второй вариант завершения программы.

Для завершения программы без вызова обработчиков, зарегистрированных с помощью функции atexit, можно использовать функцию _Exit. Данная функция задекларирована следующим образом:
void _Exit(int).

В качестве параметра функция принимает код возврата, с которым программа и завершается.
Как я уже упоминал: функции-обработчики не вызываются. Рассмотрим пример кода:

int k=0;

void exit1(){
printf("At function exit1 %d\n",k++);
}

void exit2(){
printf("At function exit2 %d\n",k++);
}

void exit3(){
printf("At function exit3 %d\n",k++);
}

void exit4(){
printf("At function exit4 %d\n", k++);
}

typedef void (* Func_t)(void);

int main (int argc, const char * argv[]) {

Func_t arr[4]={exit1, exit2, exit3, exit4};

int i=0;

for(i=0;i<4;++i)
atexit(arr[i]);

for(i=0;i<10;++i)
if(i==5){
printf("%d",i);
_Exit(0);
}
printf("End of program");
return 0;
}

При выполнении данного кода произойдет следующее. При i==5 программа завершит свое выполнение путем вызова функции _Exit, при этом ни один из обработчиков вызван не будет. Результат выполнения приведен ниже:

[Session started at 2008-11-07 11:10:00 +0300.]

The Debugger has exited with status 0.
a silhouette of a person's head and shoulders, used as a default avatar

Использование функции exit

Рассмотрим варианты выхода из программы.

Первый вариант - это выход при помощи вызова функции exit, которая выглядит следующим образом:
void exit(int)

В качестве параметра в функцию нужно передать код возврата, с которым закончит свою работу программа.
При вызове функции программа завершает свою работу. При этом вызываются все функции, зарегистрированные с помощью функции atexit.

Пример использования:

int k=0;

void exit1(){
printf("At function exit1 %d\n",k++);
}

void exit2(){
printf("At function exit2 %d\n",k++);
}

void exit3(){
printf("At function exit3 %d\n",k++);
}

void exit4(){
printf("At function exit4 %d\n", k++);
}

Это функции - обработчики завершения программы.

typedef void (* Func_t)(void);

int main (int argc, const char * argv[]) {

Func_t arr[4]={exit1, exit2, exit3, exit4};

int i=0;

for(i=0;i<4;++i)
atexit(arr[i]);

for(i=0;i<10;++i)
if(i==5){
printf("%d",i);
exit(0);
}
printf("End of program");
}

При запуске данного кода получаем следующий результат:

5 // Печатается счетчик цикла i
At function exit4 0 // Результат выводится последним обработчиком
At function exit3 1 // Результат выводится предпоследним обработчиком
At function exit2 2 // и т.д.
At function exit1 3

a silhouette of a person's head and shoulders, used as a default avatar

Что можно почитать?

Часто возникает вопрос: А где найти информацию по языку, стандарту и т.д. В принципе, таких мест много в сети. Но если удобно работать с печатными изданиями, которые всегда под рукой, "приятно шелестят страницами", не требуют наличия соединения с сетью, да и вообще ноутбука, то я могу порекомендовать следующее:
Язык программирования C
Сэмюел П. Харбисон, Гай Л. Стил
Язык программирования C

Книга, а мой взгляд, написана очень хорошо. Полностью раскрыты возможности использования языка, приведены примеры.
Так что, эта книга заслуживает Вашего прочтения.