假设我们有一个结构体,它有一个成员指针,该指针有条件地指向内部数组或堆上的某个地方,如下所示:
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();}
保证做复制省略,所以如果 ex
上面的代码没问题是 f1()
的结果.一般来说,我建议不要依赖于此,只需为您的类提供正确的复制构造函数即可避免此类问题。
关于c++ - 不知道某些东西是否被省略会引入未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62840020/