Interesting C/C++ interview questions

tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

шпиён wrote:С первого взгляда кажется просто.
1) Лишняя аллокация/деаллокация памяти. Да еще и лик может быть, если из catch своё исключение бросится до delete.
2) Лишнее копи-конструирование, что для приведенного в примере exep не хуже копирования указателя в случае 1, но для больших/сложных классов может быть дорого.
На мой взгляд, метод 2 однозначно лучше, т.к. за расчет на высокую скорость обработки исключений надо anyway бить лопатой по голове.


похоже на правду. Вот только в случае использования варианта c указателем видится мне в приведенном коде ошибка одна... Выплывет она не обязательно, но в общем, при использовании SEH есть вероятность что выплывет. Какая?
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

tchicago wrote:Вот только в случае использования варианта c указателем видится мне в приведенном коде ошибка одна... Выплывет она не обязательно, но в общем, при использовании SEH есть вероятность что выплывет. Какая?

Поскольку пользователь может создать класс нового exception exep_new на основе базового класса exep и при этом catch operator сработает также, однако delete операция вызовет деструктор базового класса. Ещё один пример, когда лучше объявить деструктор виртуальным в базовом классе
class exep
{
public:
exep(int err) : _error(err) {}
virtual ~exep() {}
int get_code() const { return _error; }
private:
int _error;
};
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
Boriskin
Уже с Приветом
Posts: 18906
Joined: 30 Aug 2001 09:01
Location: 3rd planet

Post by Boriskin »

tchicago wrote: Вот только в случае использования варианта c указателем видится мне в приведенном коде ошибка одна...


ИМХО, если при создании объекта через new чтото произойдет, то я не уверен, что catch поймает исключение.
Тупизна как Энтропия. Неумолимо растет.
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

Boriskin wrote:
tchicago wrote: Вот только в случае использования варианта c указателем видится мне в приведенном коде ошибка одна...


ИМХО, если при создании объекта через new чтото произойдет, то я не уверен, что catch поймает исключение.

Вы имеете в виду создание через new самого объекта exception?
То есть программа кинет exception в момент создания объекта exception.
В таком случае я не вижу разницы и в том и в другом случае catch не сработает, поскольку это будет другой тип exception.
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
Boriskin
Уже с Приветом
Posts: 18906
Joined: 30 Aug 2001 09:01
Location: 3rd planet

Post by Boriskin »

То есть программа кинет exception в момент создания объекта exception.


Или new кинет недостаток памяти, что, как мне кажется, и есть самая интересная ситуация, а искать - лениво. :mrgreen:
Тупизна как Энтропия. Неумолимо растет.
User avatar
AndreyT
Уже с Приветом
Posts: 3003
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Post by AndreyT »

roadman wrote:Поскольку пользователь может создать класс нового exception exep_new на основе базового класса exep и при этом catch operator сработает также, однако delete операция вызовет деструктор базового класса. Ещё один пример, когда лучше объявить деструктор виртуальным в базовом классе


Не совсем понимаю, почему это "еще один" пример. Виртуальный деструктор, с формальной точки зрения, нужен тогда и только тогда, когда объект класса удаляется вот таким вот полиморфным образом. Так что это не "еще один" пример. Это просто очередная вариация одного и того же примера.
Best regards,
Андрей
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

AndreyT wrote:Не совсем понимаю, почему это "еще один" пример. Виртуальный деструктор, с формальной точки зрения, нужен тогда и только тогда, когда объект класса удаляется вот таким вот полиморфным образом. Так что это не "еще один" пример. Это просто очередная вариация одного и того же примера.


вот типичная ситуация:

Code: Select all

class exep 
{
public:
   exep(int err) : _error(err) {}
   int get_code() const { return _error; }
private:
   int _error;
};

class SomeLibraryClass
{
public:
   ...
   virtual void do_something()
   {
      // Does something
      ...
      throw new exep( 1 );
      ...
   }
   ...
private:
   void do_something_internally()
   {
      ...
      try
      {
         ...
         do_something();
         ..
      }
      catch( exep* ex )
      {
         ...
         delete ex;
      }
   }
};



Поскольку SomeLibraryClass подразумевает дальнейшее наследование, то вполне возможно, что автор унаследованного класса захочет определить и свои исключения. Они будут унаследованы от исключений, используемых данным классом, чтобы базовый класс мог их корректно обрабатывать. Не определив виртуальный деструктор для базового исключения мы таким образом запрещаем потомку exep иметь свой деструктор. А если потомок его определит, и будет надеяться, что он будет вызван - looming disaster.
User avatar
шпиён
Уже с Приветом
Posts: 3459
Joined: 29 Oct 2002 20:08
Location: US

Post by шпиён »

tchicago wrote:
Поскольку SomeLibraryClass подразумевает дальнейшее наследование, то вполне возможно, что автор унаследованного класса захочет определить и свои исключения. Они будут унаследованы от исключений, используемых данным классом, чтобы базовый класс мог их корректно обрабатывать. Не определив виртуальный деструктор для базового исключения мы таким образом запрещаем потомку exep иметь свой деструктор. А если потомок его определит, и будет надеяться, что он будет вызван - looming disaster.


Поэтому бросать и ловить исключение по указателю - изврат.
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

шпиён wrote:Поэтому бросать и ловить исключение по указателю - изврат.


Не изврат, а вполне разумная оптимизация.
А вот пользоваться char* строками программируя на c++ - точно изврат. :^P
User avatar
шпиён
Уже с Приветом
Posts: 3459
Joined: 29 Oct 2002 20:08
Location: US

Post by шпиён »

tchicago wrote:
шпиён wrote:Поэтому бросать и ловить исключение по указателю - изврат.


Не изврат, а вполне разумная оптимизация.
А вот пользоваться char* строками программируя на c++ - точно изврат. :^P


Оптимизация чего? 8O
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

шпиён wrote:Оптимизация чего? 8O


Количества вызываемых конструкторов копирования.

А насчет char* - сорри, это я кажется Вас с Фигли перепутал.
User avatar
шпиён
Уже с Приветом
Posts: 3459
Joined: 29 Oct 2002 20:08
Location: US

Post by шпиён »

tchicago wrote:
шпиён wrote:Оптимизация чего? 8O


Количества вызываемых конструкторов копирования.


Инлайновых, которые копируют только указатель на VMT (и, может быть, неколько байт доп. инфо)? ;) По сравнению с отведением и освобождением памяти на куче? ;)

И самое главное - зачем? Уж не думаете ли Вы, что обработка исключения сравнима с копированием нескольких байт? И её стоит иметь в performance-critical потоке исполнения? И тем более в комплекте с аллокациями-деаллокациями? :pain1:
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

шпиён wrote:
tchicago wrote:
шпиён wrote:Оптимизация чего? 8O


Количества вызываемых конструкторов копирования.


Инлайновых, которые копируют только указатель на VMT (и, может быть, неколько байт доп. инфо)? ;) По сравнению с отведением и освобождением памяти на куче? ;)

И самое главное - зачем? Уж не думаете ли Вы, что обработка исключения сравнима с копированием нескольких байт? И её стоит иметь в performance-critical потоке исполнения? И тем более в комплекте с аллокациями-деаллокациями? :pain1:


Зависит от:

a) Сложности объекта исключения. Во многих случаях это не просто несколько байт памяти.
б) Архитектуры приложения/библиотеки. Некоторые библитеки действительно используют механизм исключений для доставки пользователю результатов работы (с точки зрения разработчика библиотеки это исключительная ситуация, с точки зрения ее пользователя - нет)
в) Наличия собственного аллокатора памяти или свойств стандартного.
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Post by A. Fig Lee »

tchicago wrote:
шпиён wrote:Поэтому бросать и ловить исключение по указателю - изврат.


Не изврат, а вполне разумная оптимизация.
А вот пользоваться char* строками программируя на c++ - точно изврат. :^P

Ну если на одном С++ программируешь... А если прыгаешь с С на С++ и обратно...
Лучше уж одного стиля придерживатся.

Code: Select all

#ifndef COPY_STRING
#include <string.h>
#ifdef __cplusplus
#define COPY_STRING(TO, FROM)   {int this_len = TO?strlen(TO):0;\
   int that_len = FROM?strlen(FROM):0;\
   if (TO &&  (!FROM || (FROM && (that_len > this_len))))\
   {\
      delete [] TO; TO=NULL;\
   }\
   if (!FROM)\
   {\
      TO = NULL;\
   }else if (!TO)\
      TO = new char[that_len + 1];\
   if (FROM)\
      strcpy(TO, FROM);}

#define MOVE_STRING(TO, FROM) if (TO) delete [] TO; TO = FROM; FROM = NULL;
#else
#include <stdlib.h>
#define COPY_STRING(TO, FROM)   {int this_len = TO?strlen(TO):0;\
   int that_len = FROM?strlen(FROM):0;\
   if (TO &&  (!FROM || (FROM && (that_len > this_len))))\
   {\
      free((void*) TO); TO=NULL;\
   }\
   if (!FROM)\
   {\
      TO = NULL;\
   }else if (!TO)\
      TO = (char*) malloc(that_len + 1);\
   if (FROM)\
      strcpy(TO, FROM);}

#define MOVE_STRING(TO, FROM) if (TO) free((void*) TO); TO = FROM; FROM = NULL;

#endif
#endif
Верить нельзя никому - даже себе. Мне - можно!
User avatar
шпиён
Уже с Приветом
Posts: 3459
Joined: 29 Oct 2002 20:08
Location: US

Post by шпиён »

tchicago wrote:
шпиён wrote:
tchicago wrote:
шпиён wrote:Оптимизация чего? 8O


Количества вызываемых конструкторов копирования.


Инлайновых, которые копируют только указатель на VMT (и, может быть, неколько байт доп. инфо)? ;) По сравнению с отведением и освобождением памяти на куче? ;)

И самое главное - зачем? Уж не думаете ли Вы, что обработка исключения сравнима с копированием нескольких байт? И её стоит иметь в performance-critical потоке исполнения? И тем более в комплекте с аллокациями-деаллокациями? :pain1:


Зависит от:

a) Сложности объекта исключения. Во многих случаях это не просто несколько байт памяти.
б) Архитектуры приложения/библиотеки. Некоторые библитеки действительно используют механизм исключений для доставки пользователю результатов работы (с точки зрения разработчика библиотеки это исключительная ситуация, с точки зрения ее пользователя - нет)


А причем тут производительность? При таких условиях о ней УЖЕ мечтать не приходится.

tchicago wrote:в) Наличия собственного аллокатора памяти или свойств стандартного.


Вам известны аллокаторы, производительность которых (на new И на delete) сравнима с отсутсвием аллокации? ;)

Return to “Работа и Карьера в IT”