Нарушенное здесь правило задокументировано в C ++ 03 3.10 / 15 [basic.lval], в котором указано, что неофициально называют «правилом строгого алиасинга»
Если программа пытается получить доступ к сохраненному значению объекта через значение lvalue, отличное от одного из следующих типов, поведение не определено:
динамический тип объекта,
cv-квалифицированная версия динамического типа объекта,
тип, который является типом со знаком или без знака, соответствующим динамическому типу объекта,
тип, который является типом со знаком или без знака, соответствующим cv-квалифицированной версии динамического типа объекта,
агрегированный или объединенный тип, который включает в себя один из вышеупомянутых типов среди своих членов (включая, рекурсивно, член субагрегированного или автономного объединения),
тип, который является (возможно, cv-квалифицированным) типом базового класса динамического типа объекта,
тип char или unsigned char.
Короче говоря, для данного объекта вам разрешен доступ к этому объекту только через выражение, которое имеет один из типов в списке. Для объекта типа класса, который не имеет базовых классов, таких как std::vector<T>
, в основном вы ограничены типами, указанными в первом, втором и последнем маркерах.
std::vector<Base*>
и std::vector<Derived*>
- совершенно не связанные типы, и вы не можете использовать объект типа std::vector<Base*>
, как если бы это был std::vector<Derived*>
. Если вы нарушите это правило, компилятор может делать все что угодно, в том числе:
выполняют разные оптимизации для одной по сравнению с другой, или
выложите внутренние элементы одного из них, или
выполняет оптимизацию, предполагая, что std::vector<Base*>*
никогда не может ссылаться на тот же объект, что и std::vector<Derived*>*
использовать проверки во время выполнения, чтобы убедиться, что вы не нарушаете правило строгого алиасинга
[Он также может не выполнять ничего из этого и может «работать», но нет гарантии, что он будет «работать», и если вы измените компиляторы или версии компилятора или настройки компиляции, все это может перестать «работать». Я использую кавычки по причине здесь. : -)]
Даже если у вас просто был Base*[N]
, вы не могли бы использовать этот массив, как если бы он был Derived*[N]
(хотя в этом случае использование, вероятно, было бы более безопасным, где «более безопасный» означает «все еще не определено, но менее вероятно» чтобы доставить вам неприятности).