不知道某些东西是否被省略会引入未定义的行为吗?

Can not knowing whether something is elided introduce undefined behavior?

假设我们有一个结构,它有一个成员指针,该指针有条件地指向内部数组或堆上的某处,如下所示:

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 总是未定义的行为吗?它是否是未定义的行为取决于编译器(比如它是否决定省略)?还是定义明确的行为? (同样的问题也可能适用于第一个例子)

在复制省略不是强制性的所有情况下,当您执行以下操作时会出现未定义的行为:

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

从 c++17 开始,这个函数:

Ex f1() {return Ex();}

保证执行复制省略,因此如果 exf1().

的结果,则上面的代码没问题

一般来说,我建议不要依赖于此,只需为您的 class 提供正确的复制构造函数即可避免此类问题。