Являются ли встроенные переменные уникальными через границы?

Это продолжение этого вопроса.
Как уже упоминалось в комментариях к ответу:

Встроенная переменная имеет свойство: - Она имеет одинаковый адрес в каждой единице перевода. [...] Обычно вы достигли этого, определив переменную в файле cpp, но с помощью встроенного спецификатора вы можете просто объявить / определить свои переменные в заголовочном файле, и каждая единица перевода, использующая эту встроенную переменную, использует один и тот же объект.

Более того, из самого ответа:

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

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

Есть ли какая-либо гарантия относительно уникальности встроенной переменной, когда она используется через границы, или это просто деталь реализации, на которую я не должен полагаться?

3 ответа

Вот как я интерпретирую стандарт. Согласно basic.link/1:

Программа состоит из одного или нескольких блоков перевода, связанных вместе.

Это ничего не говорит ни о статических ссылках, ни о динамических ссылках. Программа - это единицы перевода, связанные вместе. Неважно, будет ли связывание выполнено в два этапа (сначала создайте.dll /.so, а затем динамический компоновщик связывает все динамические библиотеки + исполняемый файл вместе).

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

В Linux это правда.

В Windows это работает не во всех обстоятельствах, поэтому в моей интерпретации это нарушает стандарт в этих обстоятельствах (если вы создаете отдельную.dll, которая содержит статическую переменную, не встроенную, а все остальные.dll и exe ссылается на эту переменную, она работает).

C++ в настоящее время не имеет концепции разделяемых библиотек. Итак, путь inline Поведение в разделяемых библиотеках зависит от реализации и платформы.

Тот факт, что [basic.link]/1 утверждает, что " Программа состоит из одного или нескольких блоков перевода, связанных вместе ", не означает, что программа, связанная вместе с другим, уже связанным модулем, должна вести себя одинаково.

За эти годы было представлено много предложений по исправлению ситуации ( N1400, N1418, N1496, N1976, N2407, N3347, N4028), ни одно из которых не оторвалось от земли. Это просто сложно реализовать в общем виде, и C++ обычно старается держаться подальше от деталей реализации. Как сказал GCC:

Для целей, которые не поддерживают ни COMDAT, ни слабые символы, большинство объектов с расплывчатой ​​связью испускаются как локальные символы, чтобы избежать дублирующих ошибок определения от компоновщика. Однако этого не происходит для локальной статики в строках, так как наличие нескольких копий почти наверняка повредит.

MSVC не предоставляет никаких символов по умолчанию. Любой "внешний" символ должен быть явно объявлен в зависимости от платформы __declspec(dllexport), Из-за этого нельзя утверждать, что Windows несовместима с C++. Ни одно из правил C++ здесь не нарушено, потому что их нет.

Есть ли какая-либо гарантия относительно уникальности встроенной переменной, когда она используется через границы, или это просто деталь реализации, на которую я не должен полагаться?

Это зависит от вас, чтобы убедиться в этом (убедившись, что все объявления на самом деле одинаковы).

Компилятор, очевидно, не может проверить это, и компоновщик не беспокоится. Так что, если вы лжете компоновщику (не выполняя вышеизложенное), то у вас будут проблемы.


Хорошо, поскольку не все понимают, что я имею в виду под "ложью компоновщику", я немного уточню это.

@oliv любезно предоставил эту ссылку, которая, помимо прочего, говорит следующее (мой комментарий):

Дубликаты этих конструкций [т.е. переменные объявляют inline в нескольких TU] будут отброшены во время соединения.

Что хорошо, это то, что нам нужно. Дело в том, что вы не знаете, какие из них (очевидно, только один сохраняется, поэтому, по сути, вы не знаете, какой из них будет).

Так что, если они различаются, вы не знаете, какой из них вы собираетесь закончить, и в результате вы получите (особенно коварную форму) UB. Вот что я имел в виду под "ложью компоновщику". Потому что, объявив ваши переменные по-разному в разных TU, это именно то, что вы сделали. Упс!

Другие вопросы по тегам