Interesting C/C++ interview questions

Michael Popov
Уже с Приветом
Posts: 991
Joined: 09 Sep 2001 09:01
Location: The Earth

Post by Michael Popov »

alder wrote:... но, я надеюсь, что мысль понятна.


Мне - нет :oops: Не могли бы Вы ее как-то развернуть и популяризировать ?
Best regards,

Michael Popov
alder
Уже с Приветом
Posts: 299
Joined: 16 Jan 2002 10:01
Location: Troy, MI

Post by alder »

Michael Popov wrote:
alder wrote:... но, я надеюсь, что мысль понятна.

Мне - нет

Я пытался показать, что инкапсуляция - это вещь полезная сама по себе тем, что представляет более высокий/удобный уровень абстракции (не говоря уже о том, что IMNSHO она и является краеугольным камнем ОО). Я было начал с заезженного примера о классе Point, который прячет в себе x и y, а нам дает разные удобные методы и операторы типа distance или (-), (<<), (>>) и т.п. Но т.к. его использовал Scott Meyers в Effective C++::"Make sure base classes have virtual destructors", где он говорит "If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea." В частности он указал интересный случай, с этой Точкой - когда x и y 16-битные, то в 32-битной системе компилятор, сможет втолкнуть это в слово/регистр машины, т.е. хранить/перемещать этот объект очень эффективно, но мы сохраним все прелести высокоуровневого интерфейса для работы с точками. Виртуальный деструктор сразу все это портит добавляя никому не нужный указатель на vtable.

Примерно та же ситуация и с тем FILE-ом. Пусть например мы написали нечто типа:

Code: Select all

class file
{
public:
    file(const char *name, const char *mode) throw (IOException)
         : fh(fopen(name, mode)
         { if (!fh) throw IOException("cannot open file"); }
    ~file()  { fclose(fh); }

    void write(void *data, int len) throw (IOException);
    void read(void *data, int len) throw (IOException);

    // и т.п., я же говорил, за уши это притянуто :-)
private:
    FILE *fh;
}

При использовании этой "обертки" с точки зрения кода не будет никакой разницы, напиши Вы руками С-шный вариант открывания/закрывания и постоянной проверки ошибок, т.к. компилятор "выоптимизирует" все что мы только что написали, и к тому же для хранения этого объекта нужно _столько_же_места_ сколько и для FILE*, виртуальный деструктор все это испортит. Читать же код будет намного проще, да и будет он чуть безопаснее.
Michael Popov
Уже с Приветом
Posts: 991
Joined: 09 Sep 2001 09:01
Location: The Earth

Post by Michael Popov »

Теперь понял. Спасибо. Совершенно с Вами согласен.
По-моему еше Alex Stepanov в каком-то интервью говорил, что все ети virtual functions are evil :) Собственно из всего ОО для generic programming только incapsulation является необходимым и достаточным. Честно говоря, за мои последние 5 лет программирования на C++ ни разу не возникала необходимость проектировать системы с глубиной наследования больше 2-3, да и то в основном interfaces. Доморошенные системы с навороченными наследственными связями между классами - ето страшный сон для тех, кто их поддерживает. Единственный пример красивого ОО кода с "глубоким деревом" наследования (во загнул :)), который я видел - ето был ... Delphi VCL (no more wars :umnik1: :mrgreen: )
Best regards,

Michael Popov
alder
Уже с Приветом
Posts: 299
Joined: 16 Jan 2002 10:01
Location: Troy, MI

Post by alder »

См. ниже :oops:
Last edited by alder on 23 Apr 2003 21:19, edited 1 time in total.
alder
Уже с Приветом
Posts: 299
Joined: 16 Jan 2002 10:01
Location: Troy, MI

Post by alder »

Кстати, по теме: я как-то наткнулся на интересный сайт - Guru of the Week. Там у них в архиве множество интересных статей из которых как мне кажется можно "наковырять" очень интересные практические вопросы. Вот для примера:

Code: Select all

void f( vector<int>& v )
{
  v[0];      // A
  v.at(0);   // B
}

В чем разница между строчками А и Б?

Или, вот, чуть поинтереснее:

Code: Select all

vector<int> v;

v.reserve( 2 );
assert( v.capacity() == 2 );
v[0] = 1;
v[1] = 2;
for( vector<int>::iterator i = v.begin();
     i < v.end(); i++ )
{
  cout << *i << endl;
}

cout << v[0];
v.reserve( 100 );
assert( v.capacity() == 100 );
cout << v[0];

v[2] = 3;
v[3] = 4;
// ...
v[99] = 100;
for( vector<int>::iterator i = v.begin(); i < v.end(); i++ )
{
  cout << *i << endl;
}

Что здесь неправильно? Покритикуйте стиль. 8)
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Post by A. Fig Lee »

alder wrote:

Code: Select all

void f( vector<int>& v )
{
  v[0];      // A
  v.at(0);   // B
}

В чем разница между строчками А и Б?

А кто его знает. Не помню. Лень проверять.
По-моему, [] бросает ексептион если индекс аут оф баунд.
alder wrote:Или, вот, чуть поинтереснее:

Code: Select all

vector<int> v;

v.reserve( 2 );
assert( v.capacity() == 2 );
v[0] = 1;
v[1] = 2;
for( vector<int>::iterator i = v.begin();
     i < v.end(); i++ )
{
  cout << *i << endl;
}

cout << v[0];
v.reserve( 100 );
assert( v.capacity() == 100 );
cout << v[0];

v[2] = 3;
v[3] = 4;
// ...
v[99] = 100;
for( vector<int>::iterator i = v.begin(); i < v.end(); i++ )
{
  cout << *i << endl;
}

Что здесь неправильно? Покритикуйте стиль. 8)

Ну во-первых, не уверен reserve ресервирует стоко скоко указано - может и больше(?) - в стандарт надо лезть, со стула вставать.
2. Not sure что корректно проверять итератор на <> а не != с begin(), end() - кто его знает, как там реализовано (есть в итераторе операторы "<>" - не припомню...). Опьять же, в стандарт лезть надо.
А что там?
P.S. reserve кстати, гарантирует сохранение данных?
Может еще чего?
Верить нельзя никому - даже себе. Мне - можно!
Mongush
Уже с Приветом
Posts: 446
Joined: 04 Jan 2002 10:01
Location: Irkutsk->Rockville, MD->Dallas, TX

Post by Mongush »

alder wrote:Кстати, по теме: я как-то наткнулся на интересный сайт - Guru of the Week. Там у них в архиве множество интересных статей из которых как мне кажется можно "наковырять" очень интересные практические вопросы. Вот для примера:

Code: Select all

void f( vector<int>& v )
{
  v[0];      // A
  v.at(0);   // B
}

В чем разница между строчками А и Б?

Или, вот, чуть поинтереснее:

Code: Select all

vector<int> v;

v.reserve( 2 );
assert( v.capacity() == 2 );
v[0] = 1;
v[1] = 2;
for( vector<int>::iterator i = v.begin();
     i < v.end(); i++ )
{
  cout << *i << endl;
}

cout << v[0];
v.reserve( 100 );
assert( v.capacity() == 100 );
cout << v[0];

v[2] = 3;
v[3] = 4;
// ...
v[99] = 100;
for( vector<int>::iterator i = v.begin(); i < v.end(); i++ )
{
  cout << *i << endl;
}

Что здесь неправильно? Покритикуйте стиль. 8)


С первым примером понятно, at делает проверку, а [] нет.
Во втором примимере, что сразу бросается в глаза i++, лучше использовать ++i еще i<v.end() хотя для вектора это и скорее всего и будет работать, лучше i != v.end().
Ну и самое главное, резервирование памяти не создает элементов.
User avatar
Boriskin
Уже с Приветом
Posts: 18906
Joined: 30 Aug 2001 09:01
Location: 3rd planet

Post by Boriskin »

Приятно было увидеть!

alder wrote:
void f( vector<int>& v )
{
v[0]; // A
v.at(0); // B
}

В чем разница между строчками А и Б?


Возможно, замечание несколько в стороне, но реализации STL зависят от платформы и компилера. Пришлось как то столкнуться с тем, что под мелкомягким все было тип-топ, а на Маке (под CodeWarrior) аппа издыхала... Из-за реализации STL.
Тупизна как Энтропия. Неумолимо растет.
Hamster
Уже с Приветом
Posts: 11475
Joined: 20 Nov 2000 10:01
Location: Escondido, CA

Post by Hamster »

Предыдущие ораторы уже отметили часть ошибок в примере, хотя в основном неправильно.
В assert'ах нужно поставить >=.
Обращаться к элементам после reserve() не следует. В теории это приводит к undefined behavior. На практике у вас, скорее всего, просто потеряются значения в 0 & 1 при втором вызове reserve().
< можно использовать для итераторов с произвольным доступом, к каковым относится итератор в векторе.
В данном случае нет никакой разницы, использовать i++ или ++i.
После cout'ов в середине забыли endl.
Два раза повторять for(vector<int>::iterator i=... ) нежелательно, так как некоторым старым ( и не очень старым ) компиляторам эта конструкция не нравится.
Протоукр
Mongush
Уже с Приветом
Posts: 446
Joined: 04 Jan 2002 10:01
Location: Irkutsk->Rockville, MD->Dallas, TX

Post by Mongush »

Hamster wrote:Предыдущие ораторы уже отметили часть ошибок в примере, хотя в основном неправильно.
В assert'ах нужно поставить >=.

Почему? Помоему reserve делает capacity именно равной аргументу reserve, если конечно она не была больше.
Hamster wrote:Обращаться к элементам после reserve() не следует. В теории это приводит к undefined behavior. На практике у вас, скорее всего, просто потеряются значения в 0 & 1 при втором вызове reserve().

reserve никак не влияет на имеющиеся елементы.
Hamster wrote:< можно использовать для итераторов с произвольным доступом, к каковым относится итератор в векторе.

можно, но не хорошо с точки зрения стиля, вдруг я потом на list все захочу поменять.
Hamster wrote:В данном случае нет никакой разницы, использовать i++ или ++i.

Разница есть.

Hamster wrote:После cout'ов в середине забыли endl.
Два раза повторять for(vector<int>::iterator i=... ) нежелательно, так как некоторым старым ( и не очень старым ) компиляторам эта конструкция не нравится.

Но стандарту это не противоречет, так что это проблемы компиляторов.
Mongush
Уже с Приветом
Posts: 446
Joined: 04 Jan 2002 10:01
Location: Irkutsk->Rockville, MD->Dallas, TX

Post by Mongush »

Boriskin wrote:Приятно было увидеть!

alder wrote:
void f( vector<int>& v )
{
v[0]; // A
v.at(0); // B
}

В чем разница между строчками А и Б?


Возможно, замечание несколько в стороне, но реализации STL зависят от платформы и компилера. Пришлось как то столкнуться с тем, что под мелкомягким все было тип-топ, а на Маке (под CodeWarrior) аппа издыхала... Из-за реализации STL.

STL уже давно в стандарте, так что это разница в реализации просто разница в поддержке стандарта.
Можно написать, что то работающее под VC но не работающее под стандартом, и наоборот.
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Post by A. Fig Lee »

Mongush wrote:
Hamster wrote:Предыдущие ораторы уже отметили часть ошибок в примере, хотя в основном неправильно.
В assert'ах нужно поставить >=.

Почему? Помоему reserve делает capacity именно равной аргументу reserve, если конечно она не была больше.

Не-а. Page 485 Стандарта - не меньше! Но могет быть больше. И ето правильно!

Hamster wrote:В данном случае нет никакой разницы, использовать i++ или ++i.

Разница есть.

Нет.

А по остальным пунктам согласен.
Верить нельзя никому - даже себе. Мне - можно!
Mongush
Уже с Приветом
Posts: 446
Joined: 04 Jan 2002 10:01
Location: Irkutsk->Rockville, MD->Dallas, TX

Post by Mongush »

A. Fig Lee wrote:Не-а. Page 485 Стандарта - не меньше! Но могет быть больше. И ето правильно!

Посмотрел, убедился, согласен.
A. Fig Lee wrote:
Hamster wrote:В данном случае нет никакой разницы, использовать i++ или ++i.

Разница есть.

Нет.

Есть :)
при i++ создается временная преременая.
User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Post by A. Fig Lee »

[quote="MongushЕсть :)
при i++ создается временная преременая.[/quote]
Точно! Ничья - 1:1.
:gen1:
Верить нельзя никому - даже себе. Мне - можно!
Hamster
Уже с Приветом
Posts: 11475
Joined: 20 Nov 2000 10:01
Location: Escondido, CA

Post by Hamster »

Mongush wrote:Есть :)
при i++ создается временная преременая.


А оптимизация на что?
Протоукр

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