#c
#c
Вопрос:
Некоторое время назад у нас было это объявление (упрощенное):
Объявление 1
struct SomeType
{
// allocates Implementation in SomeType's TU
SomeType();
// ... other stuff
struct Implementation
{
std::string someAtribute1;
std::string someAtribute2;
}
std::auto_ptr< Implementation> pimpl;
};
Некоторое время спустя мы изменили объявление de на это (упрощенное):
Объявление 2
class OtherNameImplementation;
struct SomeType
{
// allocates OtherNameImplementation in SomeType's TU
SomeType();
// ... other stuff
std::auto_ptr< OtherNameImplementation> pimpl;
};
Где OtherNameImplementation
определено в SomeType
TU и имеет точно такое же определение, как SomeType::Implementation
было (в объявлении 1).
Каким-то образом мы пропустили, что SomeType
не имеет определенного деструктора, следовательно, деструктор, сгенерированный компилятором, определен в пользовательском TU.
Вопрос:
Для TU, которые были скомпилированы против ‘Declaration 1’, Существует ли какая-либо форма гарантий того, что поведение «правильное», когда во время выполнения оно использует ‘Declaration 2’.
Есть две причины, о которых я могу думать, что это, по крайней мере, кажется «работающим»:
-
Деструктор, созданный компилятором, должен делать «правильные вещи», поскольку расположение памяти одинаково для обоих типов реализации, даже если имя типа изменилось.
-
Мы не заметили никаких последствий в течение нашего тестового периода (существует несколько сотен приложений, которые имеют эту зависимость)
Наша целевая платформа — Solaris, и мы используем Sunstudio 12.
Каким-то образом мы пропустили это во время проверки кода, и я знаю, что это, по крайней мере, UB, и в идеальном мире мы определили бы деструктор для SomeType
и перекомпилировали бы каждый TU, который зависит от этого.
Обновить:
Я «перекрестно опубликовал» это на comp.lang.c , где Альф П. Штейнбах заставил меня понять, что TU, скомпилированный против ‘Declaration 2’, пропускает память (что довольно неловко). Исходя из этого, мы вернемся к ‘Declaration 1’ и перекомпилируем каждый домен, который скомпилирован по ‘Declaration 2’, следовательно, у нас нет развязки заголовка или ABI 🙂 но мы находимся в допустимом состоянии. Мы исправим это в следующем цикле выпуска.
Комментарии:
1. Помимо вопроса, который полезно задать, не можете ли вы повторно скомпилировать весь код для нового модифицированного переработанного кода? ИМХО, это очень плохая идея компилировать один фрагмент кода и связывать его с другим.
2. Это могло бы помочь, если бы вы определили TU и UB.
3. @gregg: Оба термина (или, по крайней мере, расширения обоих сокращений, единицы перевода и неопределенного поведения) четко определены стандартом C .
4. @Als Если бы мы могли, приложив небольшие усилия, я бы не задавал этот вопрос 🙂 В зависимости от результата этого, мы вполне можем быть вынуждены это сделать, и наше руководство не будет счастливо…
5. @Tomalak: Вы правы в отношении расширенных условий. Базовая точка связи. Зачем излишне запутывать вопрос?
Ответ №1:
Гарантия наложения, на которую вы ссылаетесь, хороша, если нет базовых / производных классов и виртуальных функций.
Я не думаю, что вам разрешено предполагать, что std::auto_ptr или std::string соответствуют этому.
Комментарии:
1. Я не совсем понимаю, почему std::auto_ptr или std::string не удовлетворяют этим требованиям. По крайней мере, с той реализацией, которая у нас есть (RogueWave).
2. … кроме того, деструктор для std::auto_ptr (который, вероятно, встроен) просто вызывает деструктор для «pimpl-type» (определенный в пользовательском TU), у которого нет виртуального / базового / sub. -> вызывает деструкторы для каждого атрибута (что в точности соответствует памяти), ИМХО, деструктор std::string должен вызываться правильно, если у нас пока есть гарантии. Или я вас неправильно понимаю?
3. Компилятор собирается встроить вызовы деструктора (он должен …). Я полагаю, если вы скомпилировали только с одним компилятором и никогда не отправляли исходный код, вы могли бы предположить, что компилятор, а не каждый компилятор, которому разрешено существовать.
Ответ №2:
Я «перекрестно опубликовал» это на comp.lang.c , где Альф П. Штейнбах заставил меня понять, что TU, скомпилированный против ‘Declaration 2’, пропускает память (что довольно неловко). Исходя из этого, мы вернемся к ‘Declaration 1’ и перекомпилируем каждый домен, который скомпилирован по ‘Declaration 2’, следовательно, у нас нет развязки заголовка или ABI 🙂 но мы находимся в допустимом состоянии. Мы исправим это в следующем цикле выпуска.