понедельник, 17 ноября 2008 г.
__gnu_cxx и __verbose_terminate_handler
Рассмотрим следующий код:
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
Как видно из примера, при возникновении исключительной ситуации выводится дополнительная информация о ней, что в некоторых случаях может быть полезным.
Использование 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
понедельник, 10 ноября 2008 г.
Книга по С++, которую я прочитал первой
А вот и ссылка на книгу:
В. В. Подбельский
Язык Си++
Книга по С++
Бьерн Страуструп
Язык программирования С++. Специальное издание
Эту книгу я прочитал не первой, однако, купив ее, пользуюсь постоянно.
Перегрузка операторов перенаправления из потока и в поток
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;
пятница, 7 ноября 2008 г.
Еще одна книга
Standards Institute British
The C Standard : Incorporating Technical Corrigendum 1
Если успеете запастись данной книгой на выходные, то поделитесь своими впечатлениями на тему "Мои английские выходные".
Интересная книга
Стивен Прата
Язык программирования C. Лекции и упражнения
В данной книге очень хорошо и подробно рассмотрен язык. Уделено внимание рассмотрению конкретных примеров. В принципе, эта книга может быть интересно разноуровневым специалистам. Написана известным человеком в данной области. Так что книга "на выходные" есть.
Использование функции _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.
четверг, 6 ноября 2008 г.
Использование функции 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
вторник, 4 ноября 2008 г.
Что можно почитать?
Сэмюел П. Харбисон, Гай Л. Стил
Язык программирования C
Книга, а мой взгляд, написана очень хорошо. Полностью раскрыты возможности использования языка, приведены примеры.
Так что, эта книга заслуживает Вашего прочтения.
понедельник, 3 ноября 2008 г.
Дополнение по atexit
Дополнение по atexit
int k=0;
void exit1(){
printf("At function exit1 %d\n",k++);
}
int main (int argc, const char * argv[]) {
int i=0;
for(i=0;i<400;++i)
atexit(exit1);
for(i=0;i<100;++i)
printf(".");
return 0;
}
На выходе получаем:
At function exit1 1
At function exit1 2
At function exit1 3
At function exit1 4
...
At function exit1 196
At function exit1 197
At function exit1 198
At function exit1 199
Если мы используем следующий код:
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[]) {
// insert code here...
Func_t arr[4]={exit1, exit2, exit3, exit4};
printf("Hello, World!\n");
int i=0;
int j=0;
for(j=0;j<400;++j)
for(i=0;i<4;++i)
atexit(arr[i]);
for(i=0;i<100;++i)
printf(".");
return 0;
}
В этом случае результат еще интереснее:
...
At function exit4 1596
At function exit3 1597
At function exit2 1598
At function exit1 1599
Это говорит о том, что количество функций-обработчиков - не ограничено. Все зависит от конкретной реализации.
Однако, согласно стандарту, надо помнить, что гарантировано вызывается только 32 обработчика.
Использование atexit
int atexit(void (*)(void)).
Таким образом, функция, которая может использоваться в качестве обработчика выхода из программы, не должна возвращать результатов и, кроме того, она не имеет параметров.
Пример использования:
#include
#include
void exit1(){
printf("At function exit1\n");
}
void exit2(){
printf("At function exit2\n");
}
void exit3(){
printf("At function exit3\n");
}
void exit4(){
printf("At function exit4\n");
}
int main (int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
atexit(exit1);
atexit(exit2);
atexit(exit3);
atexit(exit4);
int i=0;
for(i=0;i<100;++i)
printf(".");
return 0;
}
[Session started at 2008-11-03 22:45:28 +0300.]
Hello, World!
....................................................................................................At function exit4
At function exit3
At function exit2
At function exit1
Можно зарегистрировать до 32 обработчиков. При этом они будут вызываться в обратном порядке, т.е. последний зарегистрированный обработчик будет вызываться первым.