不知道某物是否被省略会导致未定义行为吗?

4
假设我们有一个结构体,其中有一个指针成员,根据条件可能会指向内部数组或堆上的某个位置,如下所示:
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是否总是未定义的行为?编译器是否决定它是否未定义行为(例如是否决定省略)?还是说这是明确定义的行为?(同样的问题可能也适用于第一个示例)

3
编写一个“做正确的事情”的复制构造函数,这样你就不必担心它了。 - NathanOliver
2
不要编写具有副作用的代码。一个好的代码审查者会拒绝任何试图做你所尝试的事情的代码。 - PaulMcKenzie
char* p; 改为 char* const p;,这样就可以防止出现问题。 - Eljay
1个回答

4
在不强制执行复制省略的所有情况下,当您执行以下操作时,会出现未定义行为:
auto ex = ... 
ex.data[0] = 'h';
std::cout << ex.p[0]; 

从C++17开始,该函数:

Ex f1() {return Ex();}

这里保证进行复制省略(copy-elision),所以如果exf1()的结果,则上述代码是可行的。

一般来说,我建议不要依赖此功能,而是为您的类提供正确的复制构造函数,以避免此类问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接