C++17前后对象返回时指针行为与复制消除的技术咨询
C++17前后函数返回对象的内部指针行为与复制消除关联问题
先看代码示例:
struct A { void* p; A() : p(this) {} A(const A&); // 禁用平凡可复制性 }; A f() { A x; return x; } int main() { A a; // OK: a.p指向a A b = f(); // 疑问:b.p是否可能因编译器是否应用RVO而悬垂,指向f内的x A c = A(); // (C++17之前) 疑问:若创建临时对象后销毁,c.p是否会悬垂 // (C++17起) OK: c.p直接指向c,无临时对象参与 }
具体疑问
- 在
A b = f();中,C++17之前的标准下,是否会因编译器是否应用返回值优化(RVO),导致b.p成为悬垂指针指向f函数内的x? - 对于
A c = A();,已知C17中c.p直接指向c且无临时对象,但C11/14中是否会因临时对象销毁导致c.p悬垂?
注:此代码无法在C03中编译,仅针对C11和C++14标准咨询。
解答
问题1:A b = f();的行为分析
在C++17之前,返回值优化(RVO)是编译器可选优化,标准不强制要求实现:
- 若编译器启用RVO:
f()中的x会直接在b的内存地址上构造,此时x.p(即最终的b.p)指向的就是b自身,不存在悬垂问题。 - 若编译器不启用RVO:会先在
f()栈帧内构造x(x.p指向x),再调用复制构造函数将x复制到b。如果复制构造函数采用默认实现(仅复制成员值),那么b.p会保留x的地址,而x在f()返回后会被销毁,此时b.p就会变成悬垂指针。不过你的代码仅声明了复制构造函数未定义,若走到这一步会触发链接错误。
实际开发中,主流编译器(GCC、Clang、MSVC)在优化模式下都会默认启用RVO,悬垂场景极少出现,但标准层面确实允许这种情况发生。
问题2:A c = A();的行为分析
在C++11/14中,该语句属于可选复制消除场景:
- 若编译器启用优化:会直接在
c的内存位置构造对象,跳过临时对象的创建,此时c.p指向c自身,无悬垂风险。 - 若编译器不启用优化:会先构造临时对象(
p指向临时对象),再将临时对象复制到c,随后销毁临时对象。如果复制构造函数未修改p的值,c.p会指向已销毁的临时对象,成为悬垂指针。
同样,主流编译器在优化模式下都会消除这个临时对象,但标准未强制要求,理论上存在悬垂可能。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

