Re: Немного о поиске имён линкером
От: Кодт Россия  
Дата: 10.01.18 13:36
Оценка: 9 (2)
Здравствуйте, nen777w, Вы писали:

N>Понятно что поиск имен линкер производит не локально а то в каком порядке компилятор будет собирать модули.

(а как бог на душу положит)

N>Понятно что анонимный namespace решает проблему т.к. об уникальности его имени компилятор позаботится.

N>Непонятно почему этот код допускается, почему например при генерации имен компилятор не может пометить для линкера что приоритет поиска адреса за именем нужно выполнять локально? Из-за возможности его форвардной декларации?

Вот эту фразу не распарсил.

У разных одноимённых (нарушение ODR!) классов IImpl есть одинаковые (повезло!) глобальные таблицы виртуальных функций интерфейса Ii.
Одинаковые они потому, что и та, и другая ссылаются на одно и то же имя test::IImpl::foo — в объектных файлах там символьные имена, а не локальные адреса.
Сами таблицы одноимённые и помечены как "нужно выкинуть дубликаты".

Поэтому даже если test::B::foo() проинлайнил вызов конструктора IImpl::IImpl(int), он всё равно подставил символьное имя таблицы виртуальной функции (ибо, мы помним про "выкинуть дубликаты").
Это лотерея номер раз — какой экземпляр vtable оставит линкер.
Лотерея номер два — какой адрес test::IImpl::foo() оставит линкер в оставшемся экземпляре таблицы.

Вот так нарушение ODR приводит к неопределённому поведению.

Конечно, если бы была разрешена оптимизация на стадии линковки, можно было бы посокращать и понять, что main вызывает IImpl::foo из b.cpp, там не было бы динамических вызовов, да и вообще, линкер диагностировал бы нарушение ODR и отказался бы собирать программу.
Но не судьба.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.