LINUX.ORG.RU

hpp vs cpp

 ,


0

2

Привет! Вот вброс. какие есть за и против писать все в заголовочных файлах, с шаблонами и без, и писать, использую *.cpp файлы. (ну я хочу поднять эту тему у себя, вот готовлюсь.)

если это тут возможно, изменю это сообщение и добавлю, ответы. пока что так

hpp подход

  • + ускоряет компиляцию
  • + дает возможность компилятору проверять код
  • + не нужна система сборки

cpp подход

  • - замедляет сборку
  • - обязывает иметь систему сборки, если проект не тривиален
  • - пряет определения функций от компилятора, что выключает полезные варнинги и оптимизаии
★

Отдельно предлагаю ответить на вопрос каким образом расширения файла ускоряет или замедляет компиляцию в первую очередь самому себе ;)

faq2 ★
()
Ответ на: комментарий от faq2

не понял тебя..

//file foo.hpp
#pragma once

struct foo {
  void do_something() const {}
};

// file bar.hpp
#pragma once

struct bar {
  void do_something() const {}
};

// file main.cpp
#include "foo.hpp"
#include "bar.hpp"

int main(int,char**) {
  foo f;
  bar b;
  f.do_something();
  return 1;
}

zerhud ★
() автор топика

hpp подход

  • ускоряет компиляцию

Как раз наоборот. Попробуй включить в проект header-only версии различных библиотек (fmtlib, jsoncpp и т.д.) и сравни время сборки.

m0rph ★★★★★
()
Ответ на: комментарий от faq2

Ааа, допёр, ты пытался спросить header only vs классические библиотеки.

Так это дохрена зависит от конкретного случая.

faq2 ★
()
Ответ на: комментарий от m0rph

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

zerhud ★
() автор топика

+ не нужна система сборки

Ты фанат рукописных make файлов? Это же днище. Никто в здравом уме не пишет вручную make файлы.

ox55ff ★★★★★
()
Ответ на: комментарий от zerhud

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

//file foo.hpp
#pragma once

struct foo {
  void do_something() const;
};

// file foo.cpp
#include "foo.hpp"

void foo::do_something() const {}

// file bar.hpp
#pragma once

struct bar {
  void do_something() const ;
};

// file bar.cpp
#include "bar.hpp"

void bar::do_something() const {}

// file main.cpp
#include "foo.hpp"
#include "bar.hpp"

int main(int,char**) {
  foo f;
  bar b;
  f.do_something();
  return 1;
}
zerhud ★
() автор топика
Ответ на: комментарий от ox55ff

не )) ну cmake тоже писать надо. так просто пишешь g++ main.cpp и все (ну понятно что могут быть внешние либы например, инклюды, которые так просто не найти, так что можно просто скриптик).

zerhud ★
() автор топика

hpp подход

не нужна система сборки

Только елси ты все будешь фигачить сам. А в продакшен проектах никто не пишет все сам каждый раз. Используют десятки библиотек для тех или иных. И поэтому систему сборки в этом случае использовать придется. Соответственно про этот плюс забывай.

ускоряет компиляцию

А с чего бы? Если hpp включается ровно в один cpp - то будет тоже самое, что и написать все в этом cpp. А если включать hpp в разные cpp, то чем больше всего содержится в hpp, тем больше нужно времени на компиляцию.

дает возможность компилятору проверять код

А в случае кода в cpp не дает?

cpp подход

замедляет сборку

Каким образом?

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

См. выше. Для чего-то сложнее hello world она все равно нужна.

прячет определения функций от компилятора, что выключает полезные варнинги и оптимизаии

Каким образом? При компиляции cpp будут выставленные предупреждения и оптимизации.

rumgot ★★★★★
()
Ответ на: комментарий от zerhud

Ну и как ты думешь, на чем проще будет написать проект с использованием 4-8 thirdparty библиотек, на твоем скриптике или на cmake? А если ты отложишь проект и вернешься через год, вот удовольствие будет разбираться со скриптом…

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от rumgot

Только елси ты все будешь фигачить сам.

тут суть в том, что компилируется одной командой, её просто пишешь один раз в скрипте (тут я подразумеваю что есть тесты и основной executable, поэтому по кол-ву тестов кол-во вызовов компилятора).

А с чего бы?

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

А в случае кода в cpp не дает?

да

Каким образом?

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

zerhud ★
() автор топика

Все вообще не так.

hpp (отказ от раздельной компиляции) замедляет компиляцию, остальное вообще мимо кассы.

Насчёт системы сборки - если речь о том что один cpp и остальное хидеры, то она ненужна… если в опциях не запутаетесь.

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)

Пиши в cxx. Плюсов нет, только косые крестики.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от AntonI

замедляет компиляцию

я тут говорю о том, что замедляет компиляцию отдельного файла, зато ускоряет компиляцию проекта в целом. если думаете, что это не так, то почему?

если в опциях не запутаетесь

я там выше привел пример скрипта для сборки. мне вот приходится смореть на вывод ninja чтобы понять какие опции туда cmake вставила, в таком варианте будет понятнее.

zerhud ★
() автор топика
Ответ на: комментарий от slackwarrior

опа, решение :)

есть еще ipp для тех, кто не определился :)

я просто пытаюсь собрать какие-то плюсы и минусы подходов.

кстати, народ, понятно вообще о каких подходах я говорю? )) а то может мы тут о разном говорим ))

zerhud ★
() автор топика
Ответ на: комментарий от AntonI

остальное вообще мимо кассы

что мимо кассы? там только про доступность всего ast при компиляции. это делает возможным всякие compile time проверки для которых, в противном случае, не было бы нужной информации.

zerhud ★
() автор топика
Ответ на: комментарий от zerhud

тут суть в том, что компилируется одной командой, её просто пишешь один раз в скрипте (тут я подразумеваю что есть тесты и основной executable, поэтому по кол-ву тестов кол-во вызовов компилятора).

Как собираешься подключать в свой проект thirdparty библиотеки? Тоже все руками будешь прописывать пути до файлов библиотек и параметры компиляции/линковки?

Это все тебе кажется по причине отсутствия опыта сборки больших проетков.

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

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

А в случае кода в cpp не дает? да

Что да? Обоснуй. Код в cpp не проверяется компилятором во время его компиляции? Что ты несешь?

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

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

rumgot ★★★★★
()
Ответ на: комментарий от zerhud

так что можно просто скриптик

Который сразу привяжет проект к ОС, прощай, кроссплатформенность.

В целом, аргумент о ненужности системы сборки работает, если твой проект использует исключительно header-only библиотеки, если нет — вся стройность разваливается.

Плюс замедление сборки.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от zerhud

что мимо кассы? там только про доступность всего ast при компиляции. это делает возможным всякие compile time проверки для которых, в противном случае, не было бы нужной информации.

Ты привел только пример с выходом за границы. И то это не всегда возможно, я бы даже сказал: возможно очень изредка. Давай кокретный пример и обсудим, полезны ли там предупреждения или нет.

С другой стороны ты что предлагаешь при использовании твоим проектов 5-10 других либ, тоже их каждый раз собирать? Давай какую нибудь Qt так хранить в виде хедеров. Вот забава будет это пересобирать каждый раз.

rumgot ★★★★★
()
Ответ на: комментарий от hobbit

исключительно header-only библиотеки

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

привяжет проект к ОС

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

zerhud ★
() автор топика
Ответ на: комментарий от rumgot

хотел эту тему поднять на праздниках, тогда с примерами было бы легче ))

но в целом: доступность всего ast дает больше информации. ты можешь ее использовать явно (requries, static_assert, if constexpr, consteval и прочее) и компилятор тоже может ее использовать.

zerhud ★
() автор топика
Ответ на: комментарий от rumgot

Каким образом?

Инстансы шаблонов не шарятся при линковке насколько я помню, а посему ты будешь перекомпилировать свой std::vector каждый раз в каждом своем .cpp заново

Каким образом? При компиляции cpp будут выставленные предупреждения и оптимизации.

У тебя есть обьектник, где есть только символы. Каким образом это, например, зайнлайнить?

sarevok
()
Ответ на: комментарий от hobbit

так что можно просто скриптик

Который сразу привяжет проект к ОС, прощай, кроссплатформенность.

Не, не привяжет :) просто добавится шагов «реквайрементс». Более того, модные потуги убить цмейк тащат с собой разнообразный бред типа пыхтона (потому что пионеры из фаангуглов поголовно страдают NIH синдромом и шатания от gyp к scons ехал градле через градле и далее в meson для сборки плюсовых программ и так добавляют разнообразного ненужно).

А башик уже можно везде запустить.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от faq2

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

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

zerhud ★
() автор топика
Ответ на: комментарий от zerhud

но в целом: доступность всего ast дает больше информации. ты можешь ее использовать явно (requries, static_assert, if constexpr, consteval и прочее) и компилятор тоже может ее использовать.

Это все теория. Может не может… Ты можешь привести реальный пример?

rumgot ★★★★★
()
Ответ на: комментарий от slackwarrior

А башик уже можно везде запустить.

Мда. И в винду тянуть? Отлично. Конечно это лучше cmake.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Какая тебе разница что тянуть? :) цмейк же тоже не часть винды. А так хоть скрипты писать единообразно без заклинаний на раковине повара и страданий в недошелле cmd.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от KivApple

да :) думаю это причина, по которой и появились cpp файлы вообще.

но это кажется не актуальным. плюс, если уж надо собирать в условиях, где памяти нет, то опции компиляции есть соответствующие.

и кстати, о памяти: когда линкуешь, то опции не помогут, нужно все объектники загрузить, как я понимаю, в память. то есть проект с cpp файлами может вообще не полуится собрать при каких-то условиях, а header only получится, просто очень долго. тут могу ошибаться.

zerhud ★
() автор топика
Ответ на: комментарий от zerhud

Тесты значительно проще по структуре чем приложения, ну, если специально не оверинжинирить.

Но это только один прмимер. Так же сть ЦА и нефункциональные требования всех видов и мастей.

faq2 ★
()
Ответ на: комментарий от sarevok

Инстансы шаблонов не шарятся при линковке насколько я помню, а посему ты будешь перекомпилировать свой std::vector каждый раз в каждом своем .cpp заново

Ну я там выше вообще то упомянул про шаблоны.

У тебя есть обьектник, где есть только символы. Каким образом это, например, зайнлайнить?

Мы основы сейчас будет мусолить? Хороший эффект от встраивания примитивных коротких функций, которые обычно пишут в хедерах. Кроме того, вот есть у тебя либа, написанная кем-то. С какого фига ты думаешь, что ты лучше автора решишь, какие ее функции делать встроенными, а какие нет? А вот атвор на этапе разработке своей либы сам решит, что разместить в хедере и пометить соответсвтующим образом. С другой стороны, если автор либы ты, то сам и решишь, что в хедер в виде встроенных, а что нет.

rumgot ★★★★★
()
Ответ на: комментарий от slackwarrior

Так единообразно - это больше про cmake. И кстати точно читабильнее. Это если с bash сравнивать.

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от zerhud
g++ main.cpp $main_flags -o project

Всё писать в один main.cpp не выйдет.

Получишь: sorry, unsupported: file is too large for Clang to process или просто g++ крашнется…

fsb4000 ★★★★★
()
Ответ на: комментарий от zerhud

Если собирать в несколько потоков, то компиляция требует больше памяти, чем линковка. А вот если использовать часть либ в виде уже собранных бинарей, то и компилировать будет меньше.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Не для всего он подходит (или у тебя шелл на цмейке где-то есть? :)), а если в проекте и так что-то собирается не цмейком (какой-нибудь v8 или буст) — баш это вообще не проблема, одной зависимостью больше, одной меньше. И цмейк никто не мешает пользоваться. Тут нет противоречия.

slackwarrior ★★★★★
()
Ответ на: комментарий от rumgot

С какого фига ты думаешь, что ты лучше автора решишь, какие ее функции делать встроенными, а какие нет?

Не я, а компилятор

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

sarevok
()
Ответ на: комментарий от sarevok

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

rumgot ★★★★★
()
Ответ на: комментарий от sarevok

линковка это прошлое - оно не совместимо с мощными выразительными языками.

да, вот я и пытаюсь собрать реакцию народа, чтобы быть более убедительным. надо наверное пример накидать, но у меня что-то не накидывается сейчас: я на работе.

zerhud ★
() автор топика
Ответ на: комментарий от rumgot

вот именно. а если их положить в cpp файл, то уже не станут, очевидно. также и с теми функциями, которые пишешь сам и используешь в elf.

zerhud ★
() автор топика
Ответ на: комментарий от rumgot

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

Это был один из примеров, иначе почему у нас LTO есть? Также инлайнинг функций может быть нужен именно от юзкейса. Допустим я юзаю либу и использую некую оттуда функцию лишь один раз, что может затем провернуть другие оптимизации эффективнее типо DCE.

sarevok
()
Ответ на: комментарий от rumgot

Можно. А иногда его собрать надо. Весь. И там цмейка нет :) а есть их бустовый велосипед . Который можно дергать из цмейка... а можно их обоих из баша, который просто клей в пайплайне. Вообще нет «одного правильного способа», есть 15 конкурирующих и большинство чем дальше, тем больше про дрочь вприсядку, когда для простого примера вдруг надо поднимать целый сервер или «сендбокс»... хотя рядом есть старый способ, который никуда не делся, просто работает и не делает мозги, в отличие от одептов любого «самого правильного» способа.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 2)
Ответ на: комментарий от sarevok

Это был один из примеров того, что нет необходимости тебе решать, какие функции встраивать в thirdparty либе.

rumgot ★★★★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.