Frankenstein C++: A Well-meant Experiment Gone Horribly Wrong (Borislav Stanimirov)

Download Report

Transcript Frankenstein C++: A Well-meant Experiment Gone Horribly Wrong (Borislav Stanimirov)

Франкенщайн
Един експеримент, направен с
добри намерения, но завършил
с трагични последствия.
Борислав Станимиров
Видове проблеми
•
•
•
•
•
Наследени от С
Добавени за С++
Недобавени в С++
Съществуващи в С, но махнати в С++
Непрекъснати промени в стандарта
Резултат
•
•
•
•
•
•
•
•
Бавно компилиране
Труден за писане
Ужасно бавно компилиране
Труден за четене
Невъобразимо бавно компилиране
Труден за дебъгване
Безбожно бавно компилиране
Трудности при поддръжка
Randall Munroe
http://xkcd.com/303/
Бавно компилиране
• Един от най-трудните за парсване езици
– Контекстно зависимо компилиране
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?$allocat
or@D@2@@std@@U?$less@H@2@V?$allocator@U?$pair@$$CBHV?$basic_string@DU?$c
har_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.versioncontrol.git/57643/focus=57918
• http://groups.google.com/group/comp.lang.lisp/msg/917737b7cc851
0e3?dmode=source&output=gplain