Pull to refresh

Comments 85

Тела методов в объявлении класса — кошмар номер один.
bool *ok вместо ссылки, напоминание о старом — добром C — кошмар номер два.
Очень странное варварство с потоком — кошмар номер три. Потоку надо бы сигнал послать, а не убивать его.
Тела методов в объявлении класса — кошмар номер один.

Сделано для уменьшения объема. Реальный код смотрите на гитхабе.
bool *ok вместо ссылки, напоминание о старом — добром C — кошмар номер два.

Это ваше мнение, а мое (и разработчиков Qt) — противоположное. Объясните, чем Qt-шный вариант хуже.
Потоку надо бы сигнал послать, а не убивать его.

Покажите, как: qt-project.org/doc/qt-4.8/qthread.html
Хуже тем, что это работа с сырым указателем, которая в данном случае малоуместна, так как перед каждым обращением необходимо гарантировать, что ok правильно инициализирован. Со ссылкой эти гарантии в основном обеспечивает компилятор.

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

Также поступить со всеми остальными потоками — сделать приложение действительно событийно управляемым, каким и должно быть хорошее приложение на Qt.

void f(bool *ok = 0)
{
    //тут возникла ошибка
    if (ok)
        *ok = false;
    return;
}

//далее в коде
bool ok = false;
f(&ok);

Где тут проблема? Проверка на ok на nullptr с последующим присвоением легко оборачивается в функцию.
Поймите меня правильно, я не против исключений там, где они действительно нужны, скажем, если что-то поломалось в файловой системе. Но зачем их разбрасывать направо и налево, если возникшая ситуация вовсе не исключительная, а вполне обычная, как то неправильные параметры функции?

А по поводу цикла, так он не мой, цикл то, как я в него залезу? Вы обвиняете меня в недостатках того, что сделано не мной.
Но решение я уже нашел, и за замечание благодарен: можно вызвать cppcms::service::shutdown — этот метод thread-safe.
В поддержку «void f(bool *ok = 0)» вместо «void f(bool & ok)»
1. в первом случае можно указать параметр по-умолчанию, иногда это удобно, собственно, как показано выше
2. вызов вида «f(&ok)» мне ясно говорит что «ok» будет изменяться в теле вызываемой функции,
а вот «f(ok)» — тут хз, вызывается функция с параметром который использоваться будет как простой константный или же может измениться там.
Просматривая чужой код видел подобную запись(f(ok)), на всякий случай посмотрел ее сигнатуру, увидел неконстантную ссылку, т.е. в ней изменяется эта переменная. Хотя дальше нигде не проверяется, но очевидно, это нужно сделать. Многие бы просто пропустили этот момент, а вот при записи «f(&ok)» глаз бы зацепился сразу. Ну, это из части опыта рефакторинга своего и чужого старого кода.
Хотя, если нет необходимости использования этого параметра как в первом примере и функция ничего не возвращает, конечно, лучше просто возвращать этот bool(удачно/неудачно).
Для защиты от модификации переменных есть модификатор const, нужно не забывать им пользоваться.

В противном же случае, если ваш коллега поправит у себя сигнатуру метода, дописав & к какому-то параметру, он сможет вам чего-нибудь испортить.
Да, где-то давным давно я читал о слове «const».

Но, тут же как раз вопрос не о константных параметрах, а о результате работы функции, как выше в примере.
и вы написали: «bool *ok вместо *ссылки*, напоминание о старом — добром C — кошмар номер два.»

Вот как раз о минусе передачи по *не константной ссылке* и написал. А что кто-то что-то может изменять в сигнатуре функций как ему заблагорассудится, так и не только можно «const» влепить, а сделать все что угодно с функцией, тут уже codereview необходим.

А вообще, я с вами согласен по поводу возвращения результата и избегания «выходных» параметров функции, о чем и написал ниже.
Вы видите не ту проблему. Кстати, механизм структурной обработки исключений нужен для корректной и автоматической чистки объектов, а не для того, чтобы отрабатывать кошмарные ситуации, вроде поехавшей ФС. То есть если у нас из-за кривого пользовательского ввода рассыпался сложный алгоритм, при котором много чего насоздавалось — пусть компилятор тужится с правильным вызовом деструкторов, а не программист думает «ага, тут вернулось false, вот это мы уже создали, надо удалить, а это еще не создали… я ничего не забыл???»

Здесь же у нас антипаттерн — про себя я его называю wag the dog (хвост виляет собакой) — дело в том, что тут параметр жестко влияет на логику метода — вроде как у нас есть две версии метода, и если нам передали ноль вместо указателя — мы ошибку игнорируем, а если не ноль — сообщаем о ней. Так почему бы нам просто не завести два метода, один — игнорирующий ошибку, второй — возвращающий ее.

Кстати, возвращать можно ведь и кортеж, и пару. Новый стандарт позволяет четко отделить, где у функции «входные» параметры, а где «выходные». Потом результат можно толкнуть в константую переменную, где он будет связан, защитив себя от его глупой порчи (или путаницы, когда ok от одного преобразования взяли к результату другого). А со времякой вида
bool ok;
func(&ok);
такой трюк не пройдет.

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

Тут я согласен, с возвращением пары(ошибка(bool) — результат) вполне логично. И согласен, что всегда надо разделять, точнее пытаться не использовать «выходные» параметры.
Вот вы можете негодовать, смеяться, обвинить меня в глупости, что угодно, но я скажу как думаю: человек не обязан ублажать машину. Я прикладник, и в тонкостях внутренней работы компиляторов не только не разбираюсь, но и не вижу для себя в данный момент необходимости разбираться. Конечно, если будет задача, где это потребуется — дело другое. Сейчас же меня больше волнует то, насколько легко (с моей, хочу заметить, точки зрения) читается и понимается код.

Ошибку мы не игнорируем. Метод, принимающий указатель на bool, в любом случае завершает свое выполнение, если происходит ошибка, вопрос лишь в том, устанавливаем ли мы флаг ошибки в переменную (если ссылка нулевая, то, очевидно, не устанавливаем, но из функции все равно тут же выходим). Где такое может потребоваться? Ну вот вам надо считать файл. Читаете. Функция должна вернуть содержимое, и оно обязательно должно быть не пустым. Тут нет смысла проверять флаг ошибки: если вернули пустую строку, то нас это не устраивает в любом случае, не важно, была ли ошибка при чтении, или такого файла нет, или он просто пуст. А в другом случае, если мы хотим считать файл, но он не обязан что-то содержать, нам уже очень даже важно, произошла ошибка или просто в файле ничего нет.

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

То, что околесица была — это верно, я уже признал это и исправил. Только сейчас понял, про какой именно цикл шла речь (я то думал сначала, что про внутренний цикл cppcms::service).
Так почему бы нам просто не завести два метода, один — игнорирующий ошибку, второй — возвращающий ее.


мне кажется в boost сделано прекрасно: есть метод/функция которая в качестве параметра принимает boost::error_code & и в случае ошибки пишет туда что нужно. Возвращает при этом какое-то значение. И есть функция без boost::error_code, которая выбрасывает исключение. Какая логика нужна, ту и используй.

В Qt да, они не любят исключения. У них есть обоснование, уже не помню в чём, как минимум они и в embedded, там часто экономить приходится. Поэтому всякие toInt() и принимают опциональный аргумент bool*ok, но нюанс в том, что его не нужно инициализировать, внутри он заполняется валидным значением всегда.
Во вкусовых холиварах всегда можно задать вопрос, а как поступает STL в подобных контекстах? А STL поступает, например, так:
// in std::map
pair<iterator,bool> insert (const value_type& val);
По вашей ссылке, первый пример с воркером и контроллёром наиболее уместный
почему это плохо?

Сравните кол-во программистов на скриптовых языках и C++, готовых заниматься вебом.
Сравните стоимость добавления фичи.
Несомненно на C/C++ можно и нужно выносить некоторые части приложения, возможно в виде расширения под язык, или отдельного сервиса, но надо точно понимать, зачем это нужно и стоит ли оно того, с оглядкой на будущее.
Сравните кол-во программистов на скриптовых языках и C++, готовых заниматься вебом.
Сравните стоимость добавления фичи.

А как это относится к вопросу «почему бы мне не написать сайт на C++?». Есть программист C++, готовый заниматься веб-разработкой. Что ему мешает это делать? Кому он должен платить?
Если для себя — вообще нет проблем. Я исхожу из предположения, что сервис пишется не для себя и в дальнейшем вы не знаете, с какими задачами столкнется бизнес и будете ли вы его поддерживать.
Понял вас. На мой взгляд, высокая стоимость и прочее — это все следствия. Я же попытался углядеть причину. То есть вопрос ставился в отрыве от стоимостей, бизнесов и всего этого. Примерно как «хорошо или плохо отдыхать в пятизвездочных отелях» — хорошо или плохо само по себе, а не «могу ли я это себе позволить».

P.S.: Минус не мой, увы, кармы плюсануть не хватает.
Возможно еще причиной может быть малое количество библиотек под веб-разработку на c++.
passportjs.org/ — вот вам пример node.js библиотеки, для всевозможных вариантов авторизации. Представьте такое на c++.
По сути что делают скриптовые языки: выносят весь тяжелый слой, вроде работы с сетью, памятью в тот же самый C++, и сам скрипт содержит в основном бизнес логику.

Да и на самом деле не удобно же на C++, особенно до 11 писать. Хотябы синтаксис итераторов и отсутствие auto. Я отдаленно знаком с С++ разработкой, но судя по тому же хабру — совсем недавно начали переползать на c++11.

И все еще лично для меня остается открытым вопрос профита, сколько rps, сколько тратится памяти и тд.
вопрос профита

Вот вы плохо знаете C++, но хорошо — Python (исключительно для примера), а я плохо знаю, скажем, Python, а хорошо — C++. Вам легче писать на Питоне, мне на C++. Вот и весь профит. Если в остальном нет разницы или она невелика — то зачем что-то там еще учить ради того что все так делают.
Насчет синтаксиса: во-первых, в новом стандарте появился приличный foreach, ну как полагается:
std::list<int> list;
//заполняем
for (int &x : list) {
    //что-то делаем
}

Во-вторых, у меня, например, синтаксис не вызывает какого-то отторжения. Писал я и на том же Питоне, и на JS, и на Ruby, и на Хаскеле для ознакомления. Ну, короче, ну, красивее, но чтоб прямо радугу пускать от этого — это нет. Мне главное чтобы приложение работало как надо и выглядело как надо, и чтобы не изучать на каждый новый проект ворох новых языков и технологий (если только это не требуется для того, чтобы приложение работало как надо и выглядело как надо — тут компромиссы неуместны, надо садиться и учить).

Увы, как вы и сказали, библиотек для веба в C++ мало, ужасно мало. И дальше разрыв будет только лавинообразно увеличиваться.
Я потому и упомянул c++11, что в нем появились подобные фишки.
for (std::unordered_map<std::string, std::list<std::string> >::iterator *it = foo.begin(); it != foo.end(); it++)

Это же ужас.
Ну и я привел кейс — есть куча готовых библиотек, которых нет на с++.
PS то есть реального профита в скорости/ресурсах от использования c++ у вас не наблюдается?
ох. Теперь прекрасно. Раньше было ужасно.
Даже пример выше, как есть, стал более читабельным:
for (auto it = foo.begin(); it != foo.end(); ++it) {
}


пример выше удобен когда нужно перебрать аргументы последовательно, с итератором можно поскипать что-то.
Не могу ответить на ваш вопрос, так как аналогичный сайт на других языках не писал. Но писал я его на C++ не ради скорости или снижения потребления памяти. Кушает около 30 мегабайт (это со всеми кешами статики, хотя, пока там полтора землекопа и картинок мало), нагрузку специально не замерял, стандартный убунтовский системный монитор показывал скачки до 12-15% CPU на доли секунды при рендере постов с подсветкой синтаксиса. Больше никакой статистикой, увы, не обладаю, ибо цель была несколько иная.
забавно, если писать левой пяткой то конечно.
кто мешал программисту сделать тайпдеф на контейнер и используемые часто типы вроде итератора?
ССЗП

////////// Эта часть как правило вынесена в h[pp] файл/////////////////////////////////////////////////
typedef std::unordered_map<std::string, std::list<std::string> > storage_t;
typedef storage_t::iterator iter_t;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// в результате имеем:
for (iter_t it = foo.begin(); it != foo.end(); ++it)


И да в «новом» С++11 это чуть удобней, но auto было в С++0x уже довольно давно.
Плачу горючими слезами, почему никто хабру не читает, ведь не раз уже обсуждалась тема что не надо наследовать QThread для многопоточности, но всё равно каждый кто на хабру пишет о потоках Qt так делает, нафига?!
Обсуждение выше о том что вы неправильно поток тормозите носит для меня комический характер т.к. вы его вообще совсем неправильно готовите

Вы в начале жаловались что сигналы вне QEventLoop не работают, во первых это не всегда так, во вторых есть processEvents который позволяет отработать сигналы, в третьих — сделали бы нормально потоки у вас этой проблемы бы вообще не было.

Про веб приложения на С++ — я бы не стал, т.к. приложение должно очень долго работать, да ещё и в стрессовых ситуациях.
На С++ как ни странно это сделать трудновато, т.к. может быть очень много точек отказа — банально каждый new может кинуть исключение когда сервак упрётся в память, при этом возможности С++ по обработке таких исключений весьма ограничены ( банально залогировать произвольное исключение, красиво почиститься и продолжить работу весьма большой трюк, возможности по интроспекции у С++ сильно ограничены, а тут ещё и другие потоки что-то хотят).
Решения конечно есть — микросервисная архитектура например, но честно говоря ради сайта (где всё равно главным тормозом будет БД) не вижу смысла.
Основная причина, почему многие продолжают наследоваться от QThread — ранние версии (до 4.4) имели абстрактный метод run, поэтому веселись не веселись, а наследоваться придется. Это породило кучу кода, примеров и документации, в которых авторы именно наследуются от QThread.

Что же касается того, что красивая чистка — большой трюк… ну, надо просто ее уметь готовить :-).
По ссылке на документацию от автора статьи единственный пример и уже без наследования. Продублирую:
qt-project.org/doc/qt-4.8/qthread.html

они кстати пока наследование тоже не выбросили — run() так и остался виртуальным методом. Т.е. всё как в Java: настредование от Thread — плохая практика, используйте Runnable, но если хочется, то можно и наследоваться.
По ссылке на документацию от автора статьи единственный пример и уже без наследования.

А как же вот это:
Another way to make code run in a separate thread, is to subclass QThread and reimplement run(). For example: [...]

Другой способ заставить код выполняться в отдельном потоке — унаследоваться от QThread и переопределить run(). Для примера: [...]
И дальше пример с наследованием.
банально каждый new может кинуть исключение когда сервак упрётся в память

Если следовать этой логике, то в скриптовых языках, создание каждого нового объекта может стать точкой отказа если заканчивается память, и такие объекты создаются довольно часто.
Пожалуйста, читайте хотя бы тот код, который приведен в статье. Мне известно о рекомендованном способе работы с QThread, но в данном случае он не применим: cppcms::service содержит внутри банальный цикл вида for (;;), поэтому код типа
class Worker : public QObject
{
public:
    cppcms::service service;
}

int main()
{
    QThread t;
    Worker *w = new Worker;
    w->moveToThread();
    t.start();
}

Ничего не даст.
Можно ведь зарегистрировать в Worker сигнал по которому запускать cppcms::service, а в основном потоке дергать его через QueuedConnection
Вы не понимаете, как работает event loop. Запуститься то cppcms::service запустится, только вот сразу же заблокирует собой event loop, и ни один последующий сигнал не дойдет в этот тред, пока cppcms::service::run не завершится (а завершиться он может только при помощи cppcms::service::shutdown). Так что завершить тред вызовом QThread::quit не выйдет. Можете сами попробовать.
Ну у cppcms::service есть метод post, которым можно отправить в его boost::asio::io_service указатель на функцию, в которой обрабатывать сообщения из Qtшного event loop. Но проще было бы, если бы cppcms::service позволял бы использовать методы poll/poll_one у io_service.
Хм, не знал, спасибо. Может в этом и есть смысл, но не проще ли все же сделать так, как сделал я (обновленный вариант с вызовом cppcms::service::shutdown)?
Если ничего не патчить, то ваш вариант проще в реализации, конечно.
Немного оффтоп, но все же близкая автору тема:
использовать этот механизм не получилось (сигналы и слоты вне QEventLoop не работают, а блокирующего API у QNetworkReply нет)

Я не так давно очень был расстроен по этому поводу — надо было сделать свой QQuickImageProvider, который бы качал картинки из сети (с установкой токена доступа, что не умеет Image из коробки). Так вот в нем нельзя завести QEventLoop — иначе запросы за загрузку посыплются все одновременно и все упадет где-то внутрях Qt с SIGSEGV (баг по этому поводу). Тоже пошли мысли об использовании curl'a, и это в таком-то мощном фреймворке, как Qt. Странно это.
Технически в QQmlEngine можно передать свой QNetworkAccessManager, добавить в него свой протокол с поддержкой токенов, и грузить картинки в Image через него.
UFO just landed and posted this here
Тем, что неизвестно, сколько байт должно придти. waitForReadyRead завершается сразу, как только приходит какая-то порция данных, не дожидаясь, пока придут все данные. Соответственно, неизвестно, сколько раз надо вызвать этот метод: ждем, скажем, секунду, а там может просто инет подвис, а мы решим, что передача закончена.
Хотя, даже не так. Эти методы в QNetworkReply не реализованы. Используется реализация QIODevice, которая просто сразу же возвращает false.
UFO just landed and posted this here
Хм, неужели я невидимым цветом написал? Попробую еще разок.
Эти методы в QNetworkReply не реализованы. Используется реализация QIODevice, которая просто сразу же возвращает false.
Если хотите, откройте исходники и убедитесь сами. Либо смотрите в гугле, если не верите исходникам.
UFO just landed and posted this here
UFO just landed and posted this here
reply и не узнает, что он закончил работу, без локального цикла обработки сообщений, к сожалению…

В таких ситуациях я запускаю через QtConcurrent::run, а результат получаю через QFuture::result.

Из нагруженных знаю, что okcupid.com был на C++, чем в блоге очень гордились. Перебрались на NodeJs пару лет назад.

Тоже на Паскале в Delphi начинал, а потом кореш показал PHP… Спустя 15 лет радуюсь Метеору, как ребёнок.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Конечно, Magic bytes не дают никаких гарантий, что остальное содержимое файла соответствует формату, но тут уж ничего не поделаешь.
Насколько мне известно, с этим принято справляться путём перекодирования изображения из одного формата в тот же самый. Т.е. само изображение не меняется, а все лишние добавления пропадают. А если ImageMagick (libjpeg конкретно для JPEG, т.к. ImageMagick непременно пересожмёт изображение) не может что‐то перекодировать, то это не изображение и можно смело показывать пользователю ошибку.
Это если изображение. А если видео? Архив? Еще что-то? На некоторых досках иногда поддерживаются самые разные типы файлов. Картинки то я, само собой, обрабатываю при помощи QImage, чтобы сделать превью, но с другими типами файлов это не прокатит.
В том месте, что я процитировал, вы говорили про картинки и видео. Т.е. то, что браузер будет отображать сам, а не предлагать загрузить (с последним делать не надо абсолютно ничего, просто убедитесь, что сервер посылает браузеру такие заголовки, которые вынудят последний показать диалог загрузки). Их всегда лучше перекодировать от греха подальше. Если архивы распаковываются и их содержимое отображается, то их нужно распаковать (послав пользователя при неудаче) и перекодировать содержимое. Как раз при распаковке и проверите соответствие MIME типа файлу.

И я предлагал не просто делать preview. А пересоздать (крайне желательно сделать это lossless) и выбросить нафиг оригинал.
Вспомнились e-mail бомбы с терабайтами нулей в архиве, ронявшие сервера Mail.ru в былые времена.
Монументальный труд! Я сам как-то щупал сишные тонкие фреймворки для отдачи произвольных данных over HTTP (всякие там mongoose, libwebsockets и h2o), а у вас тут полноценная CMS :)
С вашими выводами насчёт применимости C++ в вебе скорее согласен, у плюсов, скажем так, своя атмосфера, но своя специфика есть у любого языка из модных в вебе, что в питоне, что в раби.

Пара замечаний по статье:
Нужно воспользоваться методом load, но он принимает в качестве параметра std::istream
Вроде в таких случаях (когда есть строка, а нужен поток) используют std::stringstream, ибо проще (у него прямо в конструкторе аргументом строка).

Насчёт определения mime-типа загруженного файла — мне почему-то казалось, что в Qt оно есть изкоробки, но, как показал гуглинг, в 4-ой версии не было, зато появилось в пятой.
Как вам, кстати, пятая версия этого чудного фреймворка?
Спасибо за комментарий и подсказку о std::stringstream, сейчас переделаю.
Скрытый текст
Как вам, кстати, пятая версия этого чудного фреймворка?

Отличается от четвертой только нововведениями, все старое осталось таким же, как было. Пока в нововведениях особой необходимости не возникало, продолжаю использовать четвертую версию (совместимость с пятой, разумеется, поддерживаю), ибо моя старенькая система (Ubuntu 10.04) прескверно отрисовывает виджеты на пятой версии (зернистость какая-то). Но, видимо, придется искать какие-то пути решения, потому что вот тот же QMimeDatabase — хотелось бы использовать, а никак.
моя старенькая система (Ubuntu 10.04) прескверно отрисовывает виджеты на пятой версии
Попробуйте переключить растеризатор с software на opengl (или наоборот, не понмю, что там по дефолту), скорее всего проблема в нём и/или в драйверах на видео.
сразу видно человек не ищет легких путей. я о выражение «откуда руки растут»
Всегда интересовался веб-разработкой на С++, автору спасибо за статью. Хочу внести свой вклад в эту затею и поделиться ссылкой на TreeFrog Довольно таки простой MVC фреймворк на С++. Есть встроенный маппинг базы, поддержка MongoDB, кодогенерация, поддерживаются типы Qt, convention over configuration…
Спасибо за изыскания. В качестве комментария замечу, что есть на мой взгляд лишние технические подробности. Вопроса кода касаться не буду.

Вопрос о собественном опыте.
Соглашусь про Wt. Он прикольный, но на мой взгляд категорически непрактичный. Результирующая страница получается очень сложная и происходящие внутри процессы (особенно в плане взаимодействия с сервером) становятся слабо понятными. В целом и работает это не очень бодро, т.к. слишком сложно и слишком универсально.

К слову говоря, оберунть сишную FCGI либу в удобный лично для вас С++ сахар — это достаточно быстрый процесс. Просто, сурово и прозрачно, а главное — минималистичный интерфейс.

Лично мне последнее время более интересны JS Клиент + Сервер на Websocket. Если не нужно поддерживать всякие там IE6, то уже вполне с этим можно работать. Очень кажется, что все идет именно в этом направлении. Есть кстати вполне годная библиотека на эту тему.
Благодарю за комментарий.
лишние технические подробности

Так и задумывалось: показать те технические моменты, которые обычно остаются без внимания, но с которыми приходится сталкиваться почти в любом подобном проекте.
Отмечу, что в начале статьи есть ссылка.
когда-то довелось расковыривать код yatalant.ru C++/Qt, да :) больше сказать не могу, но тот шаблонизатор порой мне снится в кошмарах.
Есть такой забавный проект который наверно еще лучше показывает возможность написания web сервисов на С++

github.com/d5/node.native
И в том же стиле:
Lua: luvit.io/
C++ (более живой чем выше) github.com/plenluno/libnode
С++ (ага еще один) github.com/nodeuv/nodeuv-http


Как мне видится основная проблема — это наличие комьюнити и система пакетов.
А остальное — это типично скрипт vs native.
Наверняка тут уже писали, но попробуйте Go принцип тоже, вам понравится.
Спасибо, но нет. Это не говоря уж о том, что меня раздражает этот хомяк, или кто он там.
На мой взгляд у C++ (особенно новых его редакций) большой потенциал для веб-разработки. Из того что еще недавно попадалось: siliconframework.org/ — Silicon is a high performance, middleware oriented, C++14 http web framework
Вчера только разглядывал этот фреймворк. Вы использовали? Если да, то хотя бы в двух словах могли бы поделиться впечатлениями?
Я вообще, наверное выделю таки время и досконально пройдусь по этому списку. Вдруг правда, чего достойное появилось.
Нет, я не использовал. Все что могу сказать что вещь еще довольно новая, первый релиз был в январе 2015.
Да, возможности местами скромнее, но значит ли это, что ODB вовсе не подходит для ORM?

Ну как бы его просто нет. Отсутствует целый слой абстракций и логики, например, тот же Active Record или его замена, тот же доступ по связям, как к свойству объекта. Все те возможности ради которых нужен ORM. Или я просто не нашел? Как по мне, похоже на db layer с зачатками ORM…

Паттерн, примененный в ODB я бы назвал Passive Record )
Если верить педивикии, то от AR ожидается что-то такое:
part = new Part()
part.name = "Sample part"
part.price = 123.45
part.save()

В ODB это будет вот так:
part = new Part()
part.name = "Sample part"
part.price = 123.45
save(part)

Если для вас это существенно… то даже не знаю, что еще сказать.
Доступ по связям (One-To-Many и прочее, я верно вас понимаю?) имеется.
я смогу обратится к part.category.somefield? при связи по внешнему ключу
Ну да, предлагается самим все это слегка дописать…

#pragma db object
class employer
{
  ...

  #pragma db id
  std::string name_;
};

#pragma db object
class employee
{
  ...

  #pragma db id
  unsigned long id_;

  std::string first_name_;
  std::string last_name_;

  shared_ptr<employer> employer_;

  #pragma db not_null
  shared_ptr<employer> current_employer_;

  #pragma db value_not_null
  std::vector<shared_ptr<employer> > previous_employers_;
};

...

// Create an employer and a few employees.
//
unsigned long john_id, jane_id;
{
  shared_ptr<employer> er (new employer ("Example Inc"));
  shared_ptr<employee> john (new employee ("John", "Doe"));
  shared_ptr<employee> jane (new employee ("Jane", "Doe"));

  john->employer_ = er;
  jane->employer_ = er;

  transaction t (db.begin ());

  db.persist (er);
  john_id = db.persist (john);
  jane_id = db.persist (jane);

  t.commit ();
}

...

// Load a few employee objects and print their employer.
//
{
  session s;
  transaction t (db.begin ());

  shared_ptr<employee> john (db.load<employee> (john_id));
  shared_ptr<employee> jane (db.load<employee> (jane_id));

  cout << john->employer_->name_ << endl;
  cout << jane->employer_->name_ << endl;

  t.commit ();
}
А сгенерировать модели по таблицам и ключам вместе со связями, или, наоборот, по существующим моделям создать структуру базы?
Структура БД генерируется по моделям, в обратную сторону генерации вроде как нет. Единственный минус — генерируется вся структура разом, и притом без IF EXISTS, что взывает некоторые затруднения и заставляет прибегать к сомнительной надежности решениям.
Sign up to leave a comment.

Articles