1. Относительно компиляторов и компоновщиков
Это действительно зависит от того, как вы создаете свой исполняемый файл.
Обычно исполняемые файлы лишены всего, что не используется. Поэтому, если вы будете связывать статически (и с правильными опциями оптимизации), функции будут удалены.
Однако, если вы создадите динамическую связь, они будут там, потому что в отношении библиотеки они экспортируются и, следовательно, используются.
Что касается множественных определений, это зависит от того, является ли символ слабым. Если он слабый, компоновщик выбирает одно из определений, в противном случае он его душит.
Наконец, они, вероятно, представляют лишь незначительную часть вашей программы.
2. Как решить проблему?
Это сложная проблема, вы всегда можете использовать препроцессор для удаления некоторых вещей, но код, который усеян директивами препроцессора, действительно раздражает чтение.
Лично я бы не стал беспокоиться ... тем более, что я тоже захожу в Release (как еще отследить производственные проблемы?).
Решением может быть определение функций-нарушителей в отдельном файле, а не ссылка на них в Release. Примечание: я не думаю, что это работает для виртуальных функций, так как они, по крайней мере, используются в vtable