Загадка сборки проекта - на мин. примере
От: Shmj Ниоткуда  
Дата: 10.07.23 06:05
Оценка:
В продолжение темы
Автор: Shmj
Дата: 05.07.23
, дабы довести до логического завершения. Всем спасибо за старания.

В .Net я о стадиях сборки даже не думал. Знал что есть сборка и JIT-компиляция (вот там важно — иногда эта JIT-компиляция занимала 10 секунд, что удавалось решить Ngen-ом, причем важно было не перепутать битность платформы). А есть ли там какие стадии сборки — особо не думал об этом.

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

1. Препроцессор — раскрывает #include, #define, #if и пр.
2. Сам компилятор для каждого файла создает o-файл.
3. Линкер собирает все в единую библиотеку или exe-файл.

Оказалось что этого не достаточно, что видно из примера. Сейчас привожу максимально упрощенный пример, он из 3 файлов:

Файл demo.hpp

#pragma once

template <typename T>
class Checker
{
public:

    Checker()
    {
        static_assert(sizeof(T), "Incomplete type");
    }
};

class DerivedClass;

class BaseClass
{
public:
    //BaseClass() {}
    static void fun1();

private:
    Checker<DerivedClass> m;
};


Файл demo.cpp

#include "demo.hpp"

class DerivedClass
{
};

void BaseClass::fun1()
{
}


Файл с функцией входа:

#include "demo.hpp"

int main()
{
    BaseClass::fun1();
}


Вопрос: почему если раскомментировать контруктор по умолчанию //BaseClass() {} — оно перестает компилироваться? Оказывается без понимания стадий сборки не поймешь этого. Тут чел. приводил стадии трансляции, возможно с этим тоже связано.

Честно сказать, даже доведя до мин. примера (общими силами), я не до конца понимаю почему возникает ошибка компиляции при явном консрукторе. Примерно так — если сборщик видит явный конструктор, то он уже не ищет реализацию класса DerivedClass а просто сразу отрабатывает assert. А вот если конструктор не указать явно, то почему assert не отрабатывает?

Вот положа руку на сердце — вы понимаете логику сбоки в этом случае?
=сначала спроси у GPT=
Отредактировано 10.07.2023 6:34 Shmj . Предыдущая версия . Еще …
Отредактировано 10.07.2023 6:07 Shmj . Предыдущая версия .
Re: Стадии сборки проекта - почему это важно (на примере)
От: rg45 СССР  
Дата: 10.07.23 06:20
Оценка:
Здравствуйте, Shmj, Вы писали:

S>C C++, как оказалось, это критически важно и без этого даже не поймешь почему не работает прога. Думал хватит понимания что есть 3 стадии:


S>1. Препроцессор — раскрывает #include, #define, #if и пр.

S>2. Сам компилятор для каждого файла создает o-файл.
S>3. Линкер собирает все в единую библиотеку или exe-файл.

S>Оказалось что этого не достаточно, что видно из примера. Сейчас привожу максимально упрощенный пример, он из 3 файлов:


S>Вопрос: почему если раскомментировать контруктор по умолчанию //BaseClass() {} — оно перестает компилироваться? Оказывается без понимания стадий сборки не поймешь этого. Тут чел. приводил стадии трансляции, возможно с этим тоже связано.


S>Честно сказать, даже доведя до мин. примера (общими силами), я не до конца понимаю почему возникает ошибка компиляции при явном консрукторе. Примерно так — если сборщик видит явный конструктор, то он уже не ищет реализацию класса DerivedClass а просто сразу отрабатывает assert. А вот если конструктор не указать явно, то почему assert не отрабатывает?


S>Вот положа руку на сердце — вы понимаете логику сбоки в этом случае?


А что тут понимать, тут просто все как угол двери. Но сначала мне бы хотелось увидеть твои комментарии по поводу "Оказалось что этого не достаточно, что видно из примера". Почему знаний о трех фазах трансляции не достаточно и каким образом пример это демонстрирует?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 10.07.2023 6:35 rg45 . Предыдущая версия . Еще …
Отредактировано 10.07.2023 6:26 rg45 . Предыдущая версия .
Re: Стадии сборки проекта - почему это важно (на примере)
От: rg45 СССР  
Дата: 10.07.23 06:30
Оценка: 4 (1) +1
Здравствуйте, Shmj, Вы писали:

S>Честно сказать, даже доведя до мин. примера (общими силами), я не до конца понимаю почему возникает ошибка компиляции при явном консрукторе.


Вот тебе подсказка: добавь непосредственно перед main определение еще одной функции:

void foo()
{
    BaseClass b;
}


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

  Ответ
Компилятор генерирует дефолтные конструкторы по мере необходимости. Да, вероятно, он видит неполноту типа, но в то же время он видит, что экземпляры класса здесь не создаются, а значит, конструктор не нужен и поводов для ошибки нет. Возможно, экземпляры этого класса создаются где-то в другой единице трансляции и возможно, в том месте определение класса уже видно. И совсем другое дело, когда дефолный конструктор определен пользователем явно. В этом случае компилятор обязан его откомпилировать и во время компиляции конструктора и вылазит неполнота типа и ошибка компиляции.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 10.07.2023 6:58 rg45 . Предыдущая версия . Еще …
Отредактировано 10.07.2023 6:56 rg45 . Предыдущая версия .
Отредактировано 10.07.2023 6:53 rg45 . Предыдущая версия .
Отредактировано 10.07.2023 6:52 rg45 . Предыдущая версия .
Отредактировано 10.07.2023 6:38 rg45 . Предыдущая версия .
Re[2]: Стадии сборки проекта - почему это важно (на примере)
От: Shmj Ниоткуда  
Дата: 10.07.23 06:31
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>А что тут понимать, тут просто все как угол двери. Но сначала мне бы хотелось увидеть твои комментарии по поводу "Оказалось что этого не достаточно, что видно из примера". Что именно тебе видно, что оказалось и почему знаний о трех фазах трансляции не достаточно?


В ракурсе 3 фаз — препроцессор, компиляция, линковка — ну никак этот пример не объяснить. Где-то на стадии компиляции это начинает иметь значение. Как я представляю, компилятор делает обход несколько раз или типа того. И если конструктор определен явно — то считает что уже может выдать assert.
=сначала спроси у GPT=
Re[3]: Стадии сборки проекта - почему это важно (на примере)
От: rg45 СССР  
Дата: 10.07.23 06:36
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>В ракурсе 3 фаз — препроцессор, компиляция, линковка — ну никак этот пример не объяснить. Где-то на стадии компиляции это начинает иметь значение. Как я представляю, компилятор делает обход несколько раз или типа того. И если конструктор определен явно — то считает что уже может выдать assert.


Ну это все твои догадки, которые не попали в цель. Слово "оказалось", здесь не очень уместно, имхо.
--
Справедливость выше закона. А человечность выше справедливости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.