Здравствуйте, Awaken, Вы писали:
A>надо для собеседования A>большинство вопросов которые обычно задают, либо очень банальны ("для чего нужны смарт-пойнтеры"), A>либо из серии знаешь/не знаешь. A>интересный и умный вопрос — когда к ответу приходишь логическим путем, а не просто "знаешь" A>парочка вопросов которые мне понравились: A>-почему в С++ нельзя реализовать полноценный сборщик мусора? A>-в каких ситуациях перегрузка левого ++ лучше чем правого ++?
1. По алгоритмической сложности (не совсем C++, но рядом). Тестируемому предлагается выражениие: O(log(N)). Большинство претендентов без затруднений рассказывают, что это означает. После этого следует провокационный вопрос: "а логарифм здесь по какому основанию?" — вот тут зачастую можно повеселиться
2. По виртуальному наследованию. Откомпилируется ли следующий фрагмент:
class A{};
class B : public A{};
class C : public virtual A{};
int test[sizeof(B) == sizeof(C)];
Как раз тот случай — если немного пошевелить мозгой, то становится ясно, что при разных вариантах наследования, в т.ч. множествнного, с использованием виртуального наследования, без добавления к типу дополнительной информации, не возможно будет выполнять приведение указателей производных типов к базовым.
3. Вопрос чуть посложнее. По автоматическому выведению параметров шаблонных функций. Этот вопрос уже несколько раз проскакивал на этом форуме. Проще на примере:
template<typename T>
class A
{
typedef T Type;
};
template<typename T>
void foo(const typename A<T>::Type& t)
{
//...
}
//Где-то в коде пытаемся вызвать foo, рассчитывая, что компилятор автоматически выведет параметр шаблона:
foo(123); //error
То же самое: можно просто знать, что подобные конструкции не должны "дедьюситься" по стандарту, а можно допереть самому, если вспомнить, что у класса A может существать сколько угодно специализаций, в которых Type может определяться как угодно, дублироваться.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Справедливость выше закона. А человечность выше справедливости.
"Awaken" <12048@users.rsdn.ru> wrote in message news:2623022@news.rsdn.ru... > AR>Самая часто встречающийся баг, который проявляется в Release версии и не проявляется в Debug > > интересно когда наоборот в дебаге падает, в релизе работает. > загадка — что это может быть?
/GF, который по дефолту врубали для дебаг версий в VC6?
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Awaken, Вы писали:
AR>>Самая часто встречающийся баг, который проявляется в Release версии и не проявляется в Debug
A>интересно когда наоборот в дебаге падает, в релизе работает. A>загадка — что это может быть?
У меня есть такой макрос — RELEASE_CODE(), как раз для таких трюков
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Amon-RA, Вы писали:
КД>>Это ты про код в assert-е ?
AR>А ну да, это тоже можно. Но я имел ввиду неинициализированные переменные. Пока не промучаешься с пятоком таких багов, не будет твердой уверенности в том, что их таки надо инициализировать
Потом появляется другая трабла — предупреждение о том, что переменной присвоено значение, но оно не было использовано. Лечение
Здравствуйте, Amon-RA, Вы писали:
КД>>Это ты про код в assert-е ?
AR>А ну да, это тоже можно. Но я имел ввиду неинициализированные переменные. Пока не промучаешься с пятоком таких багов, не будет твердой уверенности в том, что их таки надо инициализировать
А если человек сразу научился всё инициализировать, тогда на вопрос ему будет сложно ответить.
Здравствуйте, Amon-RA, Вы писали:
AR>Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>>Это ты про код в assert-е ?
AR>А ну да, это тоже можно. Но я имел ввиду неинициализированные переменные. Пока не промучаешься с пятоком таких багов, не будет твердой уверенности в том, что их таки надо инициализировать
Вообще говоря, современные компиляторы дают варнинги о таких случаях. BCB вообще любит предупреждать об неиспользуемых аргументах методов.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Awaken, Вы писали:
A>надо для собеседования A>большинство вопросов которые обычно задают, либо очень банальны ("для чего нужны смарт-пойнтеры"), A>либо из серии знаешь/не знаешь. A>интересный и умный вопрос — когда к ответу приходишь логическим путем, а не просто "знаешь" A>парочка вопросов которые мне понравились: A>-почему в С++ нельзя реализовать полноценный сборщик мусора? A>-в каких ситуациях перегрузка левого ++ лучше чем правого ++?
Попроси оператор присваивания написать вот для такого обьекта:
class Struct
{ int *Massiv1,*Massiv2 ;
};
Если тебе не нравятся массивы, заданные указателем, сделай вектора.
А дальше смотри что будет:
1) Догадается ли он проверить на тождественность обьектов.
2) Освободить память присваиваемого обьекта.
3) Поймать все исключения.
4) Отловить все ситуации, когда под один массив память захватилась, а под другой нет.
5) Корректно откатить ситуацию п 4. не повредив обьект.
6) Не будет ли течь память во всяких ситуациях
Короче. в этом примере может быть 10 различных ошибок. Все я не могу вспомнить.
Если абитуриент делает не больше трех — жить будет.
Здравствуйте, Amon-RA, Вы писали:
AR>Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>>Это ты про код в assert-е ?
AR>А ну да, это тоже можно. Но я имел ввиду неинициализированные переменные.
Что показывает, что вопрос в такой форме, смысла особого не имеет
(особенно если есть четкие представления о "правильном" ответе).
Я, к примеру, уже и не помню, когда с такой проблемой сталкивался.
У нас в стандарте кодирования стоит требование инициализировать все переменные при объявлении.
Лучше тогда спросить о том какие вообще проблемы могут возникать при переходе от "дебага" в "релиз".
Насколько часто и что конкретно встречается — это зависит от команды и процессов.
Здравствуйте, Mr. None, Вы писали:
MN>1. MN>Выбор конкретной реализации виртуальной функции зависит от реального типа одного аргумента (this), поэтому виртуальные функции называют мультиметодами одного аргумента. Есть парадигма мультиметодов с несколькими аргументами. В этой парадигме конкретная реализации мультиметода зависит от сочетания реальных типов 2-ух или нескольких аргументов. Собственно можно спросить: MN>почему в C++ есть мультиметоды одного аргумента в виде виртуальных функций, но нет мультиметодов нескольких аргументов.
MN>В ответ надо ждать рассказ о том как устроена реализация виртуальных функций (описания механизма vtbl)
Не надо ждать этот рассказ. Vtbl — одна из возможных реализаций, самая дешёвая на распространённых платформах. Но С++ абстрагирован от неё, следовательно, не в этом дело.
MN> и вывод о том, что для случая с несколькими динамическими аргументами механизм vtbl явно не подходит.
Глупости. Двойная диспетчеризация (одна из стратегий мультиметодов) прекрасно ездит на обычных виртуальных функциях.
MN> И более того, вообще не существует их эффективной реализации, а поскольку язык C++ задумывался как высоко эффективный и производительный, то эта весьма удобная пардигма до сих пор не включена в стандарт.
Дело в другом.
Причина номер раз.
Есть ровно одна стратегия диспетчеризации с полиморфизмом по 1 аргументу (неважно, имеется в виду виртуальность или ad-hoc-полиморфизм времени компиляции):
— выбор сигнатуры наиболее близкого предка фактического (или формального, если это compile-time) типа аргумента.
А с полиморфизмом по 2 и более аргументам... Во время компиляции ты просто получишь заявление о неоднозначности, и привет. Разруливай сам.
Во время исполнения — стратегий уйма
1) нужна сетка сигнатур, покрывающая всё декартово произведение фактических типов
2) выбор первой подходящей сигнатуры среди множества линейно перечисленных (так устроен pattern matching у большинства ФЯ)
3) выбор множества наиболее подходящих по одному аргументу, затем среди них — наиболее подходящей по второму (двойная диспетчеризация, механизм обработки оконных сообщений)
4) всякое затейливое ранжирование (например, сперва выбираем, какой из аргументов более достоин, и затем делаем двойную диспетчеризацию)
5) выбор точного соответствия, а если его нет — выбор дефолтного варианта (pattern matching у Миранды, в какой-то степени — у языка шаблонов С++)
Ну и которую из них выбрать?
Причина номер два.
Размазанность или сосредоточенность объявления мультиметода.
Виртуальные функции объявляются рядом (внутри) объявления соответствующих классов.
Где объявлять мультиметоды?
Например, специализации шаблонов С++ можно раскидать. И перегрузки функций тоже можно раскидать.
Правда, в ряде случаев это приводит к неожиданностям — на грани или за гранью нарушения ODR. А сколько было головняка у авторов компиляторов, чтобы правильно реализовать ADL?
А в случае стратегии номер 2, ещё и порядок объявления становится неопределённым (как компилятору и линкеру в голову взбредёт).
Сосредоточить объявление мультиметода в одном месте — сделать программу немасштабируемой.
Поручить формирование мультиметода рантайму (пусть пользователь сам регистрирует сигнатуры) — честно, но некрасиво.
Поэтому чаще всего используют рукодельное воплощение стратегии номер 3, т.е. двойную диспетчеризацию.
Причём интересно, что у обработчика оконных сообщений доминантным является первый аргумент (объект-обработчик), а у классической двойной диспетчеризации, как ни странно, второй аргумент!
MN>Но я думаю — это уже бонусный вопрос повышенной сложности .
Естественно.
MN>2. Сформулировать вопрос в точности вот в такой форме: MN>Расскажите чем отличается std::list от std::vector, например, чем std::list<bool> отличается от std::vector<bool>?
MN>В ответ вы должны услышать восторженный возглас о том, что std::vector<bool> вообще стоит особняком среди векторов, так является особо извращённой и неудачной специализацией, использовать его вообще не рекомендуется, и поэтому производить сравнительный анализа списков и векторов на примере std::list<bool> и std::vector<bool> вообще не совсем корректно.
Здравствуйте, <Аноним>, Вы писали:
AR>>>Самая часто встречающийся баг, который проявляется в Release версии и не проявляется в Debug КД>>Это ты про код в assert-е ?
А>В дебажной версиях переменные нулем обычно инициализируются, а в релизе это не гарантированно. Я чаще всего сталкивался именно с этой проблемой.
Ха! Запусти под баундс-чекером, он тебе так наинициализирует... (0x5EE5, кажется).
Ещё баг — неспецифицированное поведение, связанное с порядком вычисления аргументов функции. В дебаге, как правило, используется cdecl, и аргументы вычисляются справа налево. В релизе как бог на душу положит.
Здравствуйте, Awaken, Вы писали:
A>надо для собеседования A>большинство вопросов которые обычно задают, либо очень банальны ("для чего нужны смарт-пойнтеры"), A>либо из серии знаешь/не знаешь. A>интересный и умный вопрос — когда к ответу приходишь логическим путем, а не просто "знаешь"
а кожалению, так не бывает. Либо ты задаешь конкретные вопросы по языку, либо вообще абстрагируясь от конкретного языка.
По языку всегда интересны вопросы про templates, poi, spicialization/overriding.
Ну вот, например (более-менее слодный только третий):
1.
#include <iostream>
struct S
{
void f()
{
std::cout<< "Hello, world!" << std::endl;
}
};
int main()
{
S* s = NULL;
s->f();
}
//Why this code "works" fine and outs "Hello, world!"
2.
#include <iostream>
template <class T>
void f( T t )
{
std::cout<< t << std::endl;
}
void f( int value )
{
std::cout<< value << std::endl;
}
int main()
{
f(10); //*1*
}
//What function will be called in *1*?
3.
template <class T>
struct Foo
{
typedef typename T::some_type some_type;
};
struct Bar : public Foo<Bar>
{
typedef int some_type;
};
int main()
{
Bar b;
}
A>парочка вопросов которые мне понравились: A>-почему в С++ нельзя реализовать полноценный сборщик мусора? A>-в каких ситуациях перегрузка левого ++ лучше чем правого ++?
Здравствуйте, Mr. None, Вы писали:
A>>-почему в С++ нельзя реализовать полноценный сборщик мусора? A>>-в каких ситуациях перегрузка левого ++ лучше чем правого ++?
MN>1. MN>Выбор конкретной реализации виртуальной функции зависит от реального типа одного аргумента (this), поэтому виртуальные функции называют мультиметодами одного аргумента. Есть парадигма мультиметодов с несколькими аргументами. В этой парадигме конкретная реализации мультиметода зависит от сочетания реальных типов 2-ух или нескольких аргументов. Собственно можно спросить: MN>почему в C++ есть мультиметоды одного аргумента в виде виртуальных функций, но нет мультиметодов нескольких аргументов.
1) ИМХО этот вопрос очень спорный. Кроме того лично мне не понятно нужно ли мне от сотрудника знать что такое "мультиметоды". Я же про лямбда-исчисление его не спрашиваю, и про ТКС, скажем, тоже. И даже про кинетику фенолов Короче прользя от такого вопроса не ясна
2) Твой ответ более чем спорный. Скажем dynamic_cast тоже плохо ложится на vtbl реализацию, тем не менее он есть.
Я бы ответил, что мультиметоды -- очень сложный, редкий паттерн, который, к тому же, может иметь очень много существенных подробностей реализации. Поэтому нет способа обобщить их так, чтобы всем было удобно. А сдругой стороны, можно просто довольно реализовать те или иные стратегии реализации мультиметодов непосредственно.
3) Кстати говоря, у меня на твой вопрос-ответ есть встречный вопрос. А почему рализацию мульти-методов не включили до сих пор в STL? Тут-то vtbl вроде не мешает? MN>2. Сформулировать вопрос в точности вот в такой форме: MN>Расскажите чем отличается std::list от std::vector, например, чем std::list<bool> отличается от std::vector<bool>?
ИМХО глупая подколка не имеющая практического смысла, к тому же. Лично я бы сильно убавил уважения к экзаменатору, который такие вопросы задаёт. И подумал, хочу ли я, чтобы мои коллеги были людми, которые на такие вопросы отвечают
А вообще-то три коммента у меня есть
1) Задавая "умный" вопрос стоит быть таки уверенным в его однозначном ответе. А то можно и опозорится
2) Задавая вопрос ты не только узнаёшь что-то о кандидате, но ипоказываешь кандидату что-то о себе. И стоит подумать что ты хочешь о себе рассказывать, а чего не стоит
3) Кандидат на собеседовании находится в состоянии стресса, на кой его усугублять ещё и подколками?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Awaken, Вы писали:
A>интересно когда наоборот в дебаге падает, в релизе работает. A>загадка — что это может быть?
int * p = 0;
assert( 7 != *p );
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Посторонним В., Вы писали:
A>>-почему в С++ нельзя реализовать полноценный сборщик мусора? ПВ>Хотелось бы услашать ответ на этот вопрос. ПВ>С технологией GC не знаком, но на ум приходят кольцевые ссылки и наличие в C++ деструкторов.
Я думаю, что корень зла -- невозможность узнать структуру объекта.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Awaken, Вы писали:
A>интересный и умный вопрос — когда к ответу приходишь логическим путем, а не просто "знаешь"
1) Какие соглашения о вызове совместимы с функциями с переменным числом параметров (которые ...)?
ИМХО этот вопрос задавать на собеседовании глупо
2) Если я заключу кусок кода в
extern"c" {
тут код
}
, то что-нибудь в коде поменяется?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Посторонним В., Вы писали:
ПВ>Здравствуйте, Awaken, Вы писали:
A>>надо для собеседования A>>-почему в С++ нельзя реализовать полноценный сборщик мусора?
ПВ>Хотелось бы услашать ответ на этот вопрос. ПВ>С технологией GC не знаком, но на ум приходят кольцевые ссылки и наличие в C++ деструкторов.
Имхо, это не составляет проблем, основные засады — наличие арифметики с указателями (они же хендлы объекты) и нетипибезопасность.
Например, законный (ну если и не законный, то так скажем... возможно используемый... в том или ином виде) пример:
char* p = 0;
void alloc()
{
char* l = (char*)malloc(100);
p = l + 200;
}
void use()
{
char* l = p - 200;
// ...
}
Или что-то типа такого:
A* a = 0;
B* b = 0;
void alloc()
{
char* p = (char*)malloc(100);
a = new (p + 10) A();
b = new (p + 60) B();
}
В языках со встроенной сборкой мусора нет адресной арифметики, нет inner pointer (указателей "внутрь" объекта). Если объектные хендлы — есть чётко типизированные хендлы "на начало" объекта.
В этом смысле cli::inner_ptr из c++/cli создаёт определённые трудности, но там ввели дополнительные ограничения и требования.