Может ли незнание того, что что-то упущено, ввести неопределенное поведение? - PullRequest
4 голосов
/ 10 июля 2020

Допустим, у нас есть структура с указателем на член, который условно указывает либо на внутренний массив, либо на место в куче, например:

struct Ex {
        char* p;
        char data[14];
        bool is_heap;
        Ex() : p(&data[0]), data(), is_heap(false) {}
        //etc...
};

Теперь рассмотрим эту функцию

Ex f1() {return Ex();}

Из-за исключения копирования следующий код напечатает «h»:

int main() {
        auto ex = f1();
        ex.data[0] = 'h';
        std::cout << ex.p[0];
}

Но рассмотрите следующую функцию

Ex f2() {
        auto ret = Ex();
        return ret;
}

Насколько мне известно, эта функция может быть опущена, но если это не так, следующий код будет неопределенным поведением:

int main() {
        auto ex = f2();
        ex.data[0] = 'h';
        std::cout << ex.p[0]; // maybe derefrencing dangling pointer, maybe printing out "h"?
}

Мой вопрос: всегда ли в примере 2 поведение undefined? Это зависит от компилятора, является ли это неопределенным поведением (например, если он решил исключить или нет)? или это четко определенное поведение? (те же вопросы могут относиться и к первому примеру)

1 Ответ

4 голосов
/ 10 июля 2020

Во всех случаях, когда исключение копирования не является обязательным, у вас будет неопределенное поведение, когда вы выполните:

auto ex = ... 
ex.data[0] = 'h';
std::cout << ex.p[0]; 

Начиная с c ++ 17, эта функция:

Ex f1() {return Ex();}

является гарантированно выполняет copy-elision, поэтому приведенный выше код подходит, если ex является результатом f1().

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

...