Что такое «частично перекрывающиеся объекты»? - PullRequest
12 голосов
/ 03 сентября 2011

Я просто просматривал все возможные неопределенные варианты поведения в этом потоке, и один из них -

Результат присвоения частично перекрывающимся объектам

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

Ответы [ 5 ]

4 голосов
/ 03 сентября 2011

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

Это еще более четкий пример того, как частично перекрывающиеся объекты могут возникать при использовании встроенного оператора присваивания.Этот пример не показал бы UB, если бы не ограничения частично перекрывающихся объектов.

union Y {
    int n;
    short s;
};

void test() {
    Y y;
    y.s = 3;     // s is the active member of the union
    y.n = y.s;   // Although it is valid to read .s and then write to .x
                 // changing the active member of the union, .n and .s are
                 // not of the same type and partially overlap
}

Вы можете получить потенциальное частичное перекрытие даже с объектами того же типа.Рассмотрим этот пример в случае, когда short строго больше, чем char в реализации, которая не добавляет заполнение к X.

struct X {
    char c;
    short n;
};

union Y {
    X x;
    short s;
};

void test() {
    Y y;
    y.s = 3;     // s is the active member of the union
    y.x.n = y.s; // Although it is valid to read .s and then write to .x
                 // changing the active member of the union, it may be
                 // that .s and .x.n partially overlap, hence UB.
}
2 голосов
/ 03 сентября 2011

A union является хорошим примером для этого.
Вы можете создать структуру памяти с перекрывающимися элементами.

например (из MSDN):

union DATATYPE    // Declare union type
{
    char   ch;
    int    i;
    long   l;
    float  f;
    double d;
} var1;

Теперь, если вы используете назначение char , все остальные члены не определены. Это потому, что они находятся в одном и том же блоке памяти, и вы установили фактическое значение только для его части:

DATATYPE blah;
blah.ch = 4;

Если вы затем попытаетесь получить доступ к blah.i или blah.d или blah.f , они будут иметь неопределенное значение. (потому что только первый байт, который является символом, имел свое значение)

1 голос
/ 03 сентября 2011

Это относится к проблеме псевдонимов указателей, которая запрещена в C ++ для упрощения оптимизации компиляторами. Хорошее объяснение проблемы можно найти в этой теме

0 голосов
/ 04 сентября 2011

Канонический пример использует memcpy:

char *s = malloc(100);
int i;
for(i=0; i != 100;++i) s[i] = i; /* just populate it with some data */
char *t = s + 10;  /* s and t may overlap since s[10+i] = t[i] */
memcpy(t, s, 20); /* if you are copying at least 10 bytes, there is overlap and the behavior is undefined */

Причина, по которой memcpy является неопределенным поведением, заключается в том, что нет необходимого алгоритма для выполнения копирования.В этих обстоятельствах memmove был введен в качестве безопасной альтернативы.

0 голосов
/ 03 сентября 2011

Может быть, он имеет в виду строгое правило псевдонимов?Объект в памяти не должен перекрываться с объектами другого типа.

"Строгий псевдоним - это предположение, сделанное компилятором C (или C ++), что разыменование указателей на объекты разных типов никогда не будет ссылаться наодна и та же ячейка памяти (то есть псевдонимы друг друга.) "

...