Разрешает ли стандарт неявный виртуальный деструктор, не определяемый неявным образом, когда не создаются экземпляры его класса? - PullRequest
7 голосов
/ 24 октября 2019

Размышляя о этом вопросе , я наткнулся на что-то еще, чего я не понимаю.

Стандарт говорит ...

[class.dtor] / 4

Если в классе нет объявленного пользователем деструктора, деструктор неявно объявляется как дефолтный. Неявно объявленный деструктор является встроенным открытым членом своего класса.

[class.dtor] / 10

[...]Если у класса есть базовый класс с виртуальным деструктором, его деструктор (объявленный пользователем или неявно) виртуальный.

[class.dtor] / 7

Деструктор, который по умолчанию и не определен как удаленный, неявно определяется, когда он используется odr или когда он явно установлен по умолчанию после его первого объявления.

[basic.def.odr] / 3

[...] Виртуальная функция-член используется odr, если она не является чистой. [...]

Так что теперь мне интересно, должен ли этот код скомпилироваться:

#include <memory>

struct Base {
    virtual ~Base() = default;
};

struct Bar;
struct Foo : Base {
    std::unique_ptr<Bar> bar_{};
};

https://godbolt.org/z/B0wvzd

Я бы подумалчто ~Foo() должно быть неявно определено, потому что оно является виртуальным, но оно не будет компилироваться, потому что Bar является неполным в этом TU. Тем не менее код компилируется во всех основных компиляторах.

Что мне не хватает?

1 Ответ

0 голосов
/ 26 октября 2019

Так что теперь мне интересно, должен ли этот код скомпилироваться:

Вам интересно, эта полная программа "должна" скомпилировать ?

void f();
void g() { auto ff = &f; }
int main() {}

Если вы предполагаете, что он скомпилируется, " сколько раз " вы решите, что код скомпилируется? (Это единственная истина или двойная независимая истина, которую он должен компилировать?)

  1. f() «используется» неиспользуемым способом (адрес назначается локальной переменнойэто оптимизировано далеко).
g():
        ret
g() сам по себе даже не используется

Любой «тупой» компоновщик может увидеть, что, поскольку g() не нужен, f() не нужен;при этом предполагается, что «тупой» компилятор предполагает, что f() даже необходим в g()!

И все же необъявленная функция (f()) явно использовалась ODR . Вы ожидали такого поведения реализации или «удивляетесь» и задаете вопросы по этому поводу?

Если вы не ожидали ошибок, вам, вероятно, следует переосмыслить это целое "нарушение использования ODR, которое проходит мимокомпилятор заставляет меня задуматься "вещь :

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

Что они потребность зависит от хитрости реализации, так как очевидно, что аргумент 1. выше можно усложнить, если в сложном коде нет необходимости использовать f() в g(). Я намеренно привел тривиальный пример, допустимый для -O0.

[Примечание: это сборка для g() на уровне -O0:

g():
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], OFFSET FLAT:_Z1fv
        nop
        pop     rbp
        ret

Нет зависимости от символа f(), как вы можете видеть.]

Знания зависят от уровня оптимизации и от объема данных, предоставляемых во время генерации кода (может помочь компиляция множества блоков перевода одновременно).

Дляне виртуальные функции, функция либо необходима (то есть с именем ) необходимой вещью (другой функцией или глобальным объектом, инициализированным с помощью адреса этой функции).

Для виртуальных функций получение знанийгораздо сложнее: знать, что переопределение не будет вызываться, не так тривиально, как с функцией, которая не является переопределением (включая не виртуальную функцию), так как переопределение можно вызывать с помощью «позднего связывания», когдавиртуальный вызов делается на (g) lvalue.

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

...