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