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

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

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

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

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

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

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

16

Решение

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

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

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

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

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

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

7

Другие решения

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

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

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

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

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

4

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

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

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


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

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

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

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

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

1
По вопросам рекламы [email protected]