Худшие практики в C ++, распространенные ошибки [закрыто]


35

После прочтения этой знаменитой речи Линуса Торвальдса я подумал, что на самом деле являются подводными камнями для программистов на C ++. Я явно не имею в виду опечатки или неверный поток программ, которые рассматриваются в этом вопросе и его ответах , но я обращаюсь к более высокоуровневым ошибкам, которые не обнаруживаются компилятором и не приводят к очевидным ошибкам при первом запуске, полным ошибкам проектирования, вещи, которые невероятны в C, но, вероятно, будут сделаны в C ++ новичками, которые не понимают всех последствий своего кода.

Я также приветствую ответы, указывающие на значительное снижение производительности там, где это обычно не ожидается. Пример того, что один из моих профессоров однажды рассказал мне о генераторе парсера LR (1), который я написал:

Вы использовали слишком много случаев ненужного наследования и виртуальности. Наследование делает проект намного более сложным (и неэффективным из-за подсистемы RTTI (вывод типа времени выполнения)), и поэтому его следует использовать только там, где это имеет смысл, например, для действий в таблице разбора. Поскольку вы интенсивно используете шаблоны, вам практически не нужно наследование. "


6
Некоторые из наиболее неприятных ошибок, которые вы можете сделать в C / C ++, в основном связаны с наследием C ... читать неопределенное поведение, ручное управление памятью и т. Д. Кроме того, совет профессора кажется фальшивым / неправильным (для меня, кто не эксперт C ++) - создание экземпляра шаблона должно давать нормальный класс с vtable для virtualфункций, верно?

8
Вы либо не помните, что сказал ваш профессор, либо он понятия не имел, о чем говорил. Производные классы, как правило, не должны использовать RTTI (AKA отражение), чтобы искать вещи. Если они используют виртуальные методы, в коде может потребоваться поиск в vtable для диспетчеризации, но это приводит к одной инструкции ASM на многих процессорах. Из-за проблем с кэшированием это может замедлить работу на определенную величину, но вы вряд ли когда-либо заметите накладные расходы в любых, кроме самых требовательных случаях использования. Есть много веских причин избегать C ++, но поиск в vtable не входит в их число.
Мейсон Уилер

5
@FelixDombek: Заявлено так обобщенно и повсеместно, что эта цитата вашего профессора показывает огромное количество невежества. Когда вашему дизайну нужен какой-то полиморфизм во время выполнения, использование виртуальных функций часто является лучшим выбором; когда вам это не нужно, не используйте его: вам не нужно, чтобы все методы были виртуальными только потому, что вы используете производные классы, например.
Фред Нурк

5
@ Мейсон Уилер: RTTI содержит информацию о типе, достаточную для того, чтобы иметь возможность определить, dynamic_castдолжен ли a быть успешным или нет, и несколько других вещей, но рефлексия охватывает гораздо больше, в том числе возможность извлекать информацию об атрибутах или функциях члена, что не является присутствует в C ++.
Дэвид Родригес - dribeas

5
Комментарий профессора несколько обманчив, поскольку наследование и виртуальные функции не сильно влияют на производительность. Совет использовать умеренное наследование хорошо, но это скорее проблема структуры программы, чем эффективности. Наследование, особенно с защищенными членами, примерно настолько близко, насколько вы собираетесь получить, и если вам это не нужно, вы не должны его использовать.
Дэвид Торнли

Ответы:


69

Торвальдс говорит из своей задницы здесь.


Хорошо, почему он говорит из своей задницы:

Прежде всего, его напыщенная речь - действительно ничто, но напыщенная речь. Здесь очень мало актуального контента. Единственная причина, по которой он действительно известен или даже слегка уважаем, заключается в том, что он создан Богом Linux. Его главный аргумент в том, что C ++ - дерьмо, и он любит злить людей на C ++. Конечно, нет никакой причины отвечать на это, и любой, кто считает это разумным аргументом, в любом случае не подлежит обсуждению.

Что касается того, что могло бы прозвучать как его самые объективные моменты:

  • STL и Boost - полная чушь <- что угодно. Ты идиот.
  • STL и Boost вызывают бесконечное количество боли <- смешно. Очевидно, он намеренно преувеличивает, но каково его реальное утверждение здесь? Я не знаю. Есть некоторые более чем тривиально сложные проблемы, когда вы вызываете рвоту компилятора в Spirit или что-то в этом роде, но это не более или менее трудно понять, чем отладку UB, вызванную неправильным использованием конструкций C, таких как void *.
  • Абстрактные модели, поддерживаемые C ++, неэффективны. <- Как что? Он никогда не расширяется, никогда не приводит примеров того, что он имеет в виду, он просто говорит это. BFD. Поскольку я не могу сказать, на что он ссылается, нет смысла пытаться «опровергнуть» утверждение. Это обычная мантра C фанатиков, но это не делает ее более понятной или понятной.
  • Правильное использование C ++ означает, что вы ограничиваете себя аспектами C. <- На самом деле код WORSE C ++ там делает это, так что я до сих пор не знаю WTF, о котором он говорит.

По сути, Торвальдс говорит из своей задницы. Там нет внятного аргумента о чем-либо. Ожидать серьезного опровержения такой ерунды просто глупо. Мне говорят «расширить» на опровержение чего-то, что я должен был бы расширить, если бы я сказал это. Если вы действительно, честно посмотрите на то, что сказал Торвальдс, вы увидите, что он на самом деле ничего не сказал.

То, что Бог говорит, что это не означает, что это имеет какой-то смысл или должно восприниматься более серьезно, чем если бы это сказал какой-то случайный бозо. По правде говоря, Бог - это просто еще один случайный бозо.


Отвечая на актуальный вопрос:

Вероятно, самая плохая и самая распространенная, плохая практика C ++ - это обращаться с ней как с C. Продолжение использования функций API C, таких как printf, gets (также считается плохим в C), strtok и т. Д., Не только не позволяет использовать предоставленную мощность из-за более жесткой системы типов они неизбежно приводят к дальнейшим осложнениям при попытке взаимодействия с «реальным» кодом C ++. Так что, в принципе, делайте прямо противоположное тому, что советует Торвальдс.

Научитесь использовать STL и Boost для дальнейшего обнаружения ошибок во время компиляции и для упрощения своей жизни другими общими способами (например, токенайзер Boost является как безопасным, так и лучшим интерфейсом). Это правда, что вам нужно научиться читать ошибки шаблона, что поначалу устрашает, но (по моему опыту в любом случае), откровенно говоря, намного проще, чем пытаться отлаживать что-то, что генерирует неопределенное поведение во время выполнения, что делает C api довольно легко сделать.

Не скажу, что С не так хорош. Мне конечно больше нравится C ++. C программисты любят C лучше. Есть компромиссы и субъективные лайки в игре. Там также много дезинформации и FUD, плавающих вокруг. Я бы сказал, что в C ++ все больше и больше FUD и дезинформации, но в этом отношении я предвзят. Например, проблемы «раздувания» и «производительности», которые, предположительно, есть у C ++, на самом деле не являются серьезными проблемами в большинстве случаев и, безусловно, выходят за рамки реальности.

Что касается вопросов, на которые ссылается ваш профессор, они не являются уникальными для C ++. В ООП (и в универсальном программировании) вы хотите предпочесть композицию наследованию. Наследование - это самое сильное из возможных отношений связывания, которое существует во всех языках ОО. C ++ добавляет еще один, более сильный, дружба. Полиморфное наследование должно использоваться для представления абстракций и отношений «есть», оно никогда не должно использоваться для повторного использования. Это вторая по величине ошибка, которую вы можете совершить в C ++, и она довольно большая, но далеко не уникальная для языка. Вы также можете создавать слишком сложные отношения наследования в C # или Java, и у них будут точно такие же проблемы.


1
Ironic, как и до 2007 года, git запускал только переносимые версии Linux. Ну, любая система, которая была похожа на Unix. Опять же, учитывая обстоятельства, которые привели к созданию мерзавца, я определенно не против этого.
Крис К

9
Линусу сложно найти хороших программистов на С ++, которые хотят работать на него. Интересно, почему? Я думаю, что это просто проблема типа курица и яйцо.
Бо Перссон

19

Я всегда думал, что опасность C ++ сильно преувеличена неопытным программистом C с программистами.

Да, C ++ сложнее понять, чем что-то вроде Java, но если вы программируете с использованием современных методов, довольно легко написать надежные программы. Я честно не что гораздо сложнее из времени программирования на языке C ++ , чем я в таких языках , как Java, и я часто не хватаю определенные C ++ абстракций , как шаблоны и RAII , когда я проектирую на других языках.

Тем не менее, даже после многих лет программирования на C ++, время от времени я буду делать действительно глупую ошибку, которая была бы невозможна на языке более высокого уровня. Одна распространенная ошибка в C ++ - игнорирование времени жизни объекта: в Java и C # вам, как правило, не нужно заботиться о времени жизни объекта *, потому что все объекты существуют в куче и управляются для вас волшебным сборщиком мусора.

Теперь в современном C ++ обычно вам не нужно особо заботиться о времени жизни объекта. У вас есть деструкторы и умные указатели, которые управляют временем жизни объектов для вас. В 99% случаев это прекрасно работает. Но время от времени вы будете зависать от висящего указателя (или ссылки). Например, совсем недавно у меня был объект (давайте назовем его Foo), который содержал внутреннюю переменную ссылки на другой объект (давайте назовем его Bar). В какой-то момент я тупо расставил вещи так, что Barраньше они выходили за рамки Foo, но Fooдеструктор в итоге вызвал функцию-член Bar. Излишне говорить, что все не очень хорошо.

Теперь я не могу винить в этом C ++. Это был мой собственный плохой дизайн, но суть в том, что такого рода вещи не произошли бы на управляемом языке более высокого уровня. Даже при наличии умных указателей и тому подобного вам иногда все же необходимо осознавать время жизни объекта.


* Если управляемый ресурс - это память, то есть.


8
Никогда не нужно заботиться о времени жизни объектов в Java и C #? Их GC заботится о памяти, но это только малая часть RAII для меня; посмотрите, например, на различные «одноразовые» интерфейсы этих языков.
Фред Нурк

Забота о времени жизни объекта была бы редкой в ​​Java, за исключением неудобного дизайна ее библиотеки ввода / вывода.
Ден04

Ваша проблема с висящими ссылками - это то, что мне интересно решить. Я начал обсуждение в своем блоге о направлении, которое я направляюсь, чтобы решить его (указатель обещаний). В основном я думаю, что язык мог бы использовать несколько более умных указателей. Примите участие в этом обсуждении, если вам интересно. Никто другой не был таким, каким бы то ни было ... но если это то, что вы хотели бы видеть решенным ... Я на самом деле сталкиваюсь с этой проблемой гораздо чаще, чем в 10% случаев.
Эдвард Стрендж

13

Разница в коде обычно больше связана с программистом, чем с языком. В частности, хороший программист на C ++ и программист на C придут к одинаково хорошим (даже если иным) решениям. Теперь C - более простой язык (как язык), и это означает, что меньше абстракций и больше видимости того, что на самом деле делает код.

Часть его разглагольствования (он известен своими пристрастиями к C ++) основана на том факте, что все больше людей будут браться за C ++ и писать код, фактически не понимая, что некоторые из абстракций скрывают и делают неправильные предположения.


3
Какова стоимость итерации для std::vector<bool>изменения каждого значения? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? В чем абстрагируется *it = !*it;?
Дэвид Родригес - dribeas

2
Хотя может быть несправедливо выбирать конкретные языковые мерзости, которые часто критикуют за ошибки ...
Фред Нурк,

2
@ Фред Нурк: std::vector<bool>это общеизвестная ошибка, но это действительно хороший пример того, что обсуждается: абстракции хороши, но вы должны быть осторожны с тем, что они скрывают. То же самое может и произойдет в коде пользователя. Начнем с того, что как в C ++, так и в Java я видел людей, использующих исключения для управления потоком, и код, который выглядит как вызов вложенной функции, который на самом деле является средством запуска исключения из программы спасения: void endOperation();реализовано как throw EndOperation;. Хороший программист избежит этих удивительных конструкций, но факт в том, что вы можете их найти.
Дэвид Родригес - dribeas

5
Одним из моментов Торвальдса является то, что он может прогнать новичков, просто выбрав C над C ++ (кажется, что новичков в C ++ больше), а более сложный C ++ имеет более крутую кривую обучения и больше шансов споткнуться в угловом случае. ,
Дэвид Родригес - dribeas

2
+1, это именно то, на что жалуется Линус. Он выглядит как анти-C ++, но это не совсем так. Он всего лишь анти-C ++ - программист.
Greyfade

13

Чрезмерное использование try/catchблоков.

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

Обычно это происходит от языков, таких как Java, и люди будут утверждать, что в C ++ отсутствует finalizeпредложение.

Но этот код имеет две проблемы:

  • Нужно создать fileдо try/catch, потому что вы не можете на самом деле closeфайл, который не существует в catch. Это приводит к «утечке объема», которая fileвидна после закрытия. Вы можете добавить блок, но ...: /
  • Если кто-то приходит и добавляет returnпосреди области tryдействия, файл не закрывается (вот почему люди недовольны отсутствием finalizeпредложения)

Однако в C ++ у нас есть гораздо более эффективные способы решения этой проблемы, которые:

  • в Java finalize
  • C # 's using
  • гоу defer

У нас есть RAII, чье действительно интересное свойство лучше всего суммировать как SBRM(Scoped Bound Resources Management).

Создавая класс так, чтобы его деструктор очищал ресурсы, которыми он владеет, мы не возлагаем ответственность за управление ресурсом на каждого и каждого его пользователя!

Это особенность , которую я не хватает в любом другом языке, и , вероятно, один, наиболее забыто.

Правда заключается в том, что редко требуется даже написать try/catchблок на C ++, кроме верхнего уровня, чтобы избежать завершения без регистрации.


1
Я не думаю, что это влияние Java в той же степени, что и C. (Вы можете напрямую заменить fopenи fcloseздесь.) RAII - это «правильный» способ сделать что-то здесь, но это неудобно для людей, которые хотят использовать библиотеки C из C ++ ,
dan04

Для такого типа ответа было бы уместно привести пример правильного решения.
Клаус Йоргенсен

@ ClausJørgensen: Ну, решение, к сожалению, на самом деле не «эффектное», так как оно включает в себя только File file("some.txt");и все (нет open, нет close, нет try...)
Матье М.

D также имеет RAII
Деми

@Demetri: я не слишком знаком с D, не могли бы вы объяснить, как RAII взаимодействует с сборщиком мусора? Я знаю, что в Python вы можете написать метод "deinit", однако документация предупреждает, что в случае цикла ссылок некоторые объекты не увидят вызываемый метод deinit.
Матье М.

9

Одна распространенная ошибка, которая соответствует вашим критериям, заключается в том, что вы не понимаете, как работают конструкторы копирования при работе с выделенной памятью в вашем классе. Я потерял счет времени, потраченного на исправление сбоев или утечек памяти, потому что «нуб» помещал свои объекты в карту или вектор и не писал должным образом конструкторы и деструкторы копирования.

К сожалению, C ++ полон «скрытых» ошибок, подобных этому. Но жаловаться на это все равно, что жаловаться, что вы отправились во Францию ​​и не могли понять, что говорят люди. Если вы собираетесь туда, выучите язык.


1
Я думаю, что проблема с C ++ в том, что очень легко выстрелить себе в ногу. Конечно, есть хорошие программисты на C ++, много хорошего программного обеспечения, написанного на C ++. Но очень сложно стать хорошим разработчиком на C ++. Серия «Эффективный C ++» Скотта Мейерса показывает, сколько тонкостей имеет язык.
Марко Мустапик

Я согласен. Отчасти проблема заключается в том, что многие (большинство) программистов на C ++ думают, что они знают, что делают, когда явно не знают. Вы имели в виду "Эффективный C ++"?
Генри

По крайней мере, это становится лучше с новыми довольно ограничительными правилами неявной генерации операций копирования / перемещения в C ++ 0x. Во многих случаях, нарушающих правило трех, неявная генерация операций копирования не рекомендуется и должна выдавать предупреждение.
Sellibitze

6

C ++ допускает большое разнообразие функций и стилей программирования, но это не значит, что это действительно хорошие способы использования C ++. И на самом деле, невероятно легко неправильно использовать C ++.

Его нужно изучать и понимать правильно , просто изучение на практике (или использование его так, как если бы вы использовали какой-то другой язык) приведет к неэффективному и подверженному ошибкам коду.


4

Ну ... для начала вы можете прочитать C ++ FAQ Lite

Затем несколько человек построили карьеру, написав книги о тонкостях C ++:

Херб Саттер и Скотт Мейерс, а именно.

Что касается бессмысленной напыщенной речи Торвальдса ... давай на людей, серьезно: ни на одном другом языке не было бы так много чернил, чтобы пролить свет на нюансы этого языка. Все ваши книги по Python, Ruby и Java сосредоточены на написании приложений ... ваши книги на C ++ фокусируются на глупых языковых особенностях / подсказках / ловушках.


1
Хм ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . Я бы сказал, что Ускоренный C ++ (для одного примера) фокусируется гораздо больше на том, как писать код, чем эти ...
Джерри Коффин

1
Вы привели пару примеров ресурсов, которые указывают крайние случаи на их соответствующих языках; вещи, которые выглядят странно, и вы не совсем уверены, как они будут работать (хотя список списков Python близок) ... В C ++ есть целая индустрия, указывающая на вещи, которые выглядят совершенно корректно и ведут себя не так, как вы ожидаете.
красная грязь

3

Слишком тяжелые шаблоны поначалу могут не привести к ошибкам. Однако со временем люди должны будут изменить этот код, и им будет трудно разобраться в огромном шаблоне. Именно тогда появляются ошибки - непонимание вызывает комментарии «Он компилируется и запускается», что часто приводит к почти-но-не совсем правильному коду.

Вообще, если я вижу, что я делаю трехуровневый общий шаблон, я останавливаюсь и думаю, как его можно сократить до одного. Часто проблема решается путем извлечения функций или классов.


8
Поддержание сложного кода перед лицом изменяющихся требований всегда приводит к ошибкам без особых усилий, в этом нет ничего особенного в шаблонах.
Фред Нурк

2

Предупреждение: это не столько ответ, сколько критика разговора, на который в ответе ссылается «пользователь неизвестен».

Его первое главное замечание - это (якобы) «постоянно меняющийся стандарт». В действительности все приведенные им примеры относятся к изменениям в C ++ до того, как появился стандарт. С 1998 года (когда был завершен первый стандарт C ++) изменения в языке были весьма минимальными - на самом деле, многие утверждают, что реальная проблема заключается в том, что нужно было вносить больше изменений. Я достаточно уверен, что весь код, который соответствует исходному стандарту C ++, все еще соответствует текущему стандарту. Хотя это несколько менее определенно, если что-то не изменится быстро (и совершенно неожиданно), то же самое будет в значительной степени верно и с будущим стандартом C ++ (теоретически, весь код, который использовалexportсломается, но практически не существует; с практической точки зрения это не проблема). Я могу представить несколько других языков, операционных систем (или многое другое, связанное с компьютером), которые могут претендовать на подобные заявления.

Затем он входит в «постоянно меняющиеся стили». Опять же, большинство его пунктов довольно близко к чепухе. Он пытается охарактеризовать for (int i=0; i<n;i++)как «старый и разоренный» и for (int i(0); i!=n;++i)«новый жар». Реальность такова, что хотя существуют типы, для которых такие изменения могут иметь смысл, для них intэто не имеет значения - и даже когда вы можете что-то получить, это редко необходимо для написания хорошего или правильного кода. Даже в лучшем случае он делает гору из мухи слона.

Его следующее утверждение заключается в том, что C ++ «оптимизирует в неправильном направлении», в частности, что, хотя он признает, что использовать хорошие библиотеки легко, он утверждает, что C ++ «делает написание хороших библиотек практически невозможным». Здесь, я считаю, это одна из его самых фундаментальных ошибок. На самом деле, написание хороших библиотек практически для любого языка чрезвычайно сложно. Как минимум, написание хорошей библиотеки требует понимания некоторой проблемной области настолько хорошо, что ваш код работает для множества возможных приложений в этой области (или связанных с ними). Большая часть того, что в действительности делает C ++ , - это «поднять планку» - увидев, насколько лучше может быть библиотека , люди редко желают вернуться к написанию того вида мерзости, который они имели бы в противном случае.действительно хорошие программисты пишут довольно много библиотек, которые могут быть использованы (как он сам признает) «остальными из нас». Это действительно тот случай, когда «это не ошибка, это особенность».

Я не буду пытаться поразить каждую точку по порядку (это заняло бы страницы), но я перейду прямо к его точке закрытия. Он цитирует Бьярне: «Оптимизация всей программы может использоваться для устранения неиспользуемых таблиц виртуальных функций и данных RTTI. Такой анализ особенно подходит для относительно небольших программ, которые не используют динамическое связывание».

Он критикует это, делая неподтвержденное утверждение, что «это действительно сложная проблема», даже если сравнивать ее с проблемой остановки. На самом деле, ничего подобного - на самом деле это сделал компоновщик, включенный в Zortech C ++ (в значительной степени первый компилятор C ++ для MS-DOS еще в 1980-х годах). Это правда, что трудно быть уверенным в том, что каждый бит, возможно, посторонних данных был удален, но все же вполне разумно делать довольно честную работу.

Независимо от этого, однако, гораздо более важным моментом является то, что в любом случае это совершенно не имеет значения для большинства программистов. Как известно тем из нас, кто разбирал довольно много кода, если вы не пишете на языке ассемблера вообще без библиотек, ваши исполняемые файлы почти наверняка содержат достаточное количество «материала» (как кода, так и данных, в типичных случаях), который вы вероятно, даже не знаю о, не говоря уже о том, чтобы на самом деле использовать. Для большинства людей в большинстве случаев это не имеет значения - если вы не разрабатываете для самых маленьких встроенных систем, то дополнительное потребление памяти просто не имеет значения.

В конце концов, это правда, что эта напыщенная речь имеет немного больше субстанции, чем идиотизм Линуса - но это дает ему именно проклятие со слабой похвалой, которого оно заслуживает.


1

Как программист на C, которому приходилось кодировать на C ++ из-за неизбежных обстоятельств, вот мой опыт. Я очень мало использую C ++ и в основном придерживаюсь C. Основная причина в том, что я не очень хорошо понимаю C ++. У меня не было / не было наставника, чтобы показать мне тонкости C ++ и как написать хороший код в нем. И без руководства из очень-очень хорошего кода на C ++ очень сложно написать хороший код на C ++. ИМХО, это самый большой недостаток C ++, потому что трудно найти хороших программистов на C ++, желающих поддерживать начинающих.

Некоторые хиты производительности, которые я видел, обычно связаны с магическим распределением памяти в STL (да, вы можете изменить распределитель, но кто это делает, когда он начинает с C ++?). Специалисты C ++ обычно слышат аргументы о том, что векторы и массивы имеют одинаковую производительность, потому что векторы используют массивы внутренне, а абстракция суперэффективна. Я обнаружил, что это верно на практике для векторного доступа и изменения существующих значений. Но это не так для добавления новой записи, построения и уничтожения векторов. gprof показал, что в совокупности 25% времени для приложения было потрачено на конструкторы векторов, деструкторы, memmove (для перемещения всего вектора для добавления нового элемента) и другие перегруженные операторы векторов (например, ++).

В том же приложении векторthingSmall использовался для представления чего-то большого. Не было необходимости произвольного доступа к чему-то маленькому в чем-то большом. Тем не менее вместо списка использовался вектор. Причина, почему вектор был использован? Потому что оригинальный кодер был знаком с массивом, подобным синтаксису векторов, и не очень знаком с итераторами, необходимыми для списков (да, он из C-фона). Продолжаем доказывать, что для правильного понимания C ++ требуется много рекомендаций от экспертов. C предлагает так мало базовых конструкций без каких-либо абстракций, что вы можете сделать это намного проще, чем C ++.


0

Хотя мне нравится Линус Торвальдс, эта напыщенная речь бессмысленна - просто напыщенная речь.

Если вам нравится смотреть подробные заявления, вот один из них: «Почему C ++ вреден для окружающей среды, вызывает глобальное потепление и убивает щенков» http://chaosradio.ccc.de/camp2007_m4v_1951.html Дополнительные материалы: http: // www .fefe.de / C ++ /

Занимательный разговор, imho


0

STL и boost являются переносимыми, на уровне исходного кода. Я думаю, о чем говорит Линус, так это о том, что в C ++ отсутствует ABI (двоичный интерфейс приложения). Поэтому вам нужно скомпилировать все библиотеки, с которыми вы связываетесь, с той же версией компилятора и с теми же ключами, либо ограничить себя C ABI в границах dll. Я также нахожу это раздражающим ... но если вы не создаете сторонние библиотеки, вы должны иметь возможность контролировать свою среду сборки. Я считаю, что ограничивать себя в C ABI не стоит. Удобство возможности передавать строки, векторы и интеллектуальные указатели из одной библиотеки DLL в другую стоит того, чтобы перестраивать все библиотеки при обновлении компиляторов или переключателей компилятора. Золотые правила, которым я следую:

Наследовать, чтобы повторно использовать интерфейс, а не реализацию

-Предпочтение агрегации по наследованию

-Предпочитайте, где это возможно, свободные функции для методов-членов.

-Всегда используйте идиому RAII, чтобы сделать ваш код строго исключительным. Избегайте попытки поймать.

-Используйте умные указатели, избегайте голых (не принадлежащих) указателей

-Предпочитайте семантику значений для ссылки

-Не изобретай велосипед заново, используй stl и boost

-Используйте идиому Pimpl, чтобы скрыть приватный и / или обеспечить брандмауэр компилятора


-6

Не ставить финал ;в конце клауз-декларации, по крайней мере, в некоторых версиях VC.


4
Возможно, это очень распространенная ошибка для новичков (как и почти для тех, кто все еще изучает основной синтаксис), но есть ли многие, кто назвал бы себя компетентным и все же нашел бы эту ошибку заслуживающей внимания?
Фред Нурк

1
Написал это только потому, что компилятор выдал ошибку, которая не имеет ничего общего с отсутствием точки с запятой.
Марко Мустапик

2
да, та же самая ошибка - то, что вы получаете от компилятора Си.
Мирча Chirea
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.