Alexey Bovanenko
posted at
__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
Как видно из примера, при возникновении исключительной ситуации выводится дополнительная информация о ней, что в некоторых случаях может быть полезным.
Рассмотрим следующий код:
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
Как видно из примера, при возникновении исключительной ситуации выводится дополнительная информация о ней, что в некоторых случаях может быть полезным.
Alexey Bovanenko
posted at
Использование 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
Функция 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
Alexey Bovanenko
posted at
Книга по С++, которую я прочитал первой
Нашел я и книгу, которую прочитал первой при изучении языка С++. Она мне нравилась простотой и последовательностью изложения. Ее удобно использовать, изучая язык. Мне это в ней и нравилось. В настоящее время я, к сожалению, ее уже не имею в своем распоряжении, чтобы подробнее описать. Причина отсутствия: "подарил школьной библиотеке". Так что в школе, где я учился и работал, стало на одну книгу по С++ больше. "Отличный язык в широкие массы!!!".
А вот и ссылка на книгу:

В. В. Подбельский
Язык Си++
А вот и ссылка на книгу:

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

Бьерн Страуструп
Язык программирования С++. Специальное издание
Эту книгу я прочитал не первой, однако, купив ее, пользуюсь постоянно.

Бьерн Страуструп
Язык программирования С++. Специальное издание
Эту книгу я прочитал не первой, однако, купив ее, пользуюсь постоянно.
Alexey Bovanenko
posted at
Перегрузка операторов перенаправления из потока и в поток
Когда мы используем вывод на консоль, то часто пишем следующий код:
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;
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;
Alexey Bovanenko
posted at
Еще одна книга
Читать на русском хорошо. Но читать техническую литературу на английском приходится чаще. Можно попрактиковаться при чтении стандарта языка С на английском языке. Соответствующая ссылка приведена ниже:

Standards Institute British
The C Standard : Incorporating Technical Corrigendum 1
Если успеете запастись данной книгой на выходные, то поделитесь своими впечатлениями на тему "Мои английские выходные".

Standards Institute British
The C Standard : Incorporating Technical Corrigendum 1
Если успеете запастись данной книгой на выходные, то поделитесь своими впечатлениями на тему "Мои английские выходные".
Alexey Bovanenko
posted at
Интересная книга
Хочется поделиться еще одной интересной книгой, которая в настоящий момент доступна для чтения:

Стивен Прата
Язык программирования C. Лекции и упражнения
В данной книге очень хорошо и подробно рассмотрен язык. Уделено внимание рассмотрению конкретных примеров. В принципе, эта книга может быть интересно разноуровневым специалистам. Написана известным человеком в данной области. Так что книга "на выходные" есть.

Стивен Прата
Язык программирования C. Лекции и упражнения
В данной книге очень хорошо и подробно рассмотрен язык. Уделено внимание рассмотрению конкретных примеров. В принципе, эта книга может быть интересно разноуровневым специалистам. Написана известным человеком в данной области. Так что книга "на выходные" есть.
Alexey Bovanenko
posted at
Использование функции _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.
Для завершения программы без вызова обработчиков, зарегистрированных с помощью функции 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.
Alexey Bovanenko
posted at
Использование функции 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
Первый вариант - это выход при помощи вызова функции 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
Alexey Bovanenko
posted at
Что можно почитать?
Часто возникает вопрос: А где найти информацию по языку, стандарту и т.д. В принципе, таких мест много в сети. Но если удобно работать с печатными изданиями, которые всегда под рукой, "приятно шелестят страницами", не требуют наличия соединения с сетью, да и вообще ноутбука, то я могу порекомендовать следующее:

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

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