270 likes | 408 Views
Франкенщайн. Един експеримент, направен с добри намерения, но завършил с трагични последствия. Борислав Станимиров. Видове проблеми. Наследени от С Добавени за С++ Недобавени в С++ Съществуващи в С, но махнати в С++ Непрекъснати промени в стандарта. Резултат. Бавно компилиране
E N D
Франкенщайн Един експеримент, направен с добри намерения, но завършил с трагични последствия. Борислав Станимиров
Видове проблеми • Наследени от С • Добавени за С++ • Недобавени в С++ • Съществуващи в С, но махнати в С++ • Непрекъснати промени в стандарта
Резултат • Бавно компилиране • Труден за писане • Ужасно бавно компилиране • Труден за четене • Невъобразимо бавно компилиране • Труден за дебъгване • Безбожно бавно компилиране • Трудности при поддръжка
Бавно компилиране • Един от най-трудните за парсване езици • Контекстно зависимо компилиране a b(c); //? x->y(z); //?? • Овърлоуд на оператори • Темплейти • Рекурсивни темплейти template<class T> struct Loop { Loop<T*> operator->(); }; Loop<int> a, b = a->die;
Много бавно компилиране • Нуждата от #include, наследена от С • Разделение между хедъри и сорс-файлове • Едно и също нещо се компилира много пъти • Нуждата от forward декларации
Compiling!... class X { public: ... private: void Underpants(); Guts m_Guts; ... }; • Липса на разкаченост • Липса на енкапсулация • Често прекомпилиране
Труден за писане • Липса на вградени типове от високо ниво • Съществуват много имплементации • Изискват се много познания за имплементациите • Неочаквани извиквания на овърлоуднати функции • Нужда от виртуални деструктори
Труден за писане Student* GetStudent(int id); Student* GetStudent(const std::string& name); ... GetObject("Kiro"); //!
Труден за писане #include <list> #include <string> #include <algorithm> using namespace std; void foo(list<string>& x) { sort(x.begin(),x.end()); }
/usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h: In func\ tion ’void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std\ ::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’: big-error.C:8: instantiated from here /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2829: er\ ror: no match for ’operator-’ in ’__last - __first’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h: In func\ tion ’void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAc\ cessIterator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<ch\ ar> > >]’: /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2831: \ instantiated from ’void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessI\ terator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’ big-error.C:8: instantiated from here /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2436: er\ ror: no match for ’operator-’ in ’__last - __first’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2438: er\ ror: no match for ’operator+’ in ’__first + 16’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2439: er\ ror: no match for ’operator+’ in ’__first + 16’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h: In func\ tion ’void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIt\ erator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’: /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2442: \ instantiated from ’void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [w\ ith _RandomAccessIterator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std:\ :allocator<char> > >]’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2831: \ instantiated from ’void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessI\ terator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’ big-error.C:8: instantiated from here /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2352: er\ ror: no match for ’operator+’ in ’__first + 1’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2442: \ instantiated from ’void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [w\ ith _RandomAccessIterator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std:\ :allocator<char> > >]’ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2831: \ instantiated from ’void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessI\ terator = std::_List_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’ big-error.C:8: instantiated from here /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.2.1/../../../../include/c++/4.2.1/bits/stl_algo.h:2358: er\ ror: no match for ’operator+’ in ’__i + 1’
Труден за писане • Липсващ символ при линкване test.obj : error LNK2019: unresolved external symbol "class std::map<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > > & __cdecl fill_ar(class std::map<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > > const &)" (?fill_ar@@YAAAV?$map@HV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@U?$less@H@2@V?$allocator@U?$pair@$$CBHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@std@@@2@@std@@ABV12@@Z) referenced in function _main • Начинаещи се сблъскват с тези грешки
Труден за писане • Виртуални функции в конструктори и деструктори • Инициализацията става по реда в класа, а не по реда на изписване • Липса на автоматично менажиране на паметта • Потокът cin има дефиниран оператор void* !
Труден за писане • Обработка на изключения • Неизчистена памет с delete[], при изключение в деструктор • Нужда от автоматични указатели • Няма друг начин да укажем грешка при конструиране
Труден за писане • Стандартна библиотека • Итераторите не зная нищо за конейнера • С cout не може да се зададе ред на параметрите (за чуждоезични текстове) • Няма начин да се инициализират с литерал • Различни имплементации • Не е стандартна библиотека. • Компилира се бавно :)
Труден за писане • Дублирани функционалности със С • Макроси – темплейти – инлайн функции • Указатели – псевдоними • сhar* и string • “Зли” неща: • Идват от С • Лесно могат да подлъжат някого • Причиняват сериозни проблеми, подлъгвайки • С++ предоставя нови, частично дублиращи ги функционалности, заменяйки старите проблеми с нови, по-лоши проблеми • Не можем без “Злите” неща.
Труден за четене • Труден за парсване, значи ужасно труден за четене • Какво прави това: a = b->c(d);
Тудрен за чтеене a = b->c(d); • а е цяло число • b е обект от някакъв клас • с е метод
Truden za 4etene a = b->c(d); • а е псевдоним към цяло число (изведнъж нещо някъде се променя) • b може да е обект от клас с предефиниран оператор -> • с може да е typedef в обекта на b, така че всъщност тук конструираме нов обект
Труден за четене a = b->c(d); • Десетки други неща • Как са намесени неймспейси в случая? • Кое с от всичките възможни е това? • Какви имплицитни конверсии стават тук? • С или С++ ? ...
Труден за дебъгване • С++ няма стандартизиран бинарен изход • Трудно се правят дебъгери • Трудно се ползват дебъгери • Трудно се пишат библиотеки и компилатори
Труден за дебъгване • Няма reflection • Не може ясно да се определи типа на нещо • При обработка на изключение не може да има стек на извикванията • Нужда от интрузивна сериализация • Злия брат-близнак инвалид RTTI
Труден за дебъгване • Лесно може да се пише в чужда памет • Лесно можем да получим “изтичане” на памет • Няма вградени типове (пак) • Итераторите не знаят нищо за контейнерите (пак)
Алтернативи • C • D ( http://www.digitalmars.com/ ) • C# • Java • Boo ( http://boo.codehaus.org/ ) • Ruby ( http://www.ruby-lang.org/en/ ) • Python ( http://www.python.org/ )
Източници • http://yosefk.com/c++fqa/ • http://www.fefe.de/c++/c++-talk.pdf • http://www.nothings.org/computer/cpp.html • http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918 • http://groups.google.com/group/comp.lang.lisp/msg/917737b7cc8510e3?dmode=source&output=gplain