链式重载成员访问operator->时临时对象的生存期问题
C++中operator->重载的合法性与临时对象生存期解析
先看你提供的代码示例:
struct A { int data; A* operator->() { return this; } }; struct B { A operator->() { return A(); } }; struct C { B operator->() { return B(); } }; int main() { C()->data = 1; }
1. 重载operator->()返回this指针是否合法?有哪些潜在问题?
完全合法。C++标准对operator->()的返回值要求只有两个:要么是指针类型,要么是重载了operator->()的类/结构体类型。A*属于指针类型,完全符合语法规则,编译器不会抛出错误。
但这种写法确实存在明显的悬垂指针风险:如果调用operator->()的A对象是临时对象(比如示例中B::operator->()返回的A()),那么当这个临时对象的生存期结束后,返回的this指针就会变成无效的悬垂指针。后续如果通过这个指针访问成员,会触发未定义行为——不过在你的示例表达式里,赋值操作是在临时对象存活期间完成的,所以不会触发这个问题。
2. 链式重载operator->()中的临时对象生存期有何标准保证?
C++标准有明确规定:临时对象的生存期会延续到包含它的完整表达式结束时,不会在求值过程中中途销毁。
回到你的核心疑问:表达式C()->data = 1的求值过程不会被拆分成“先存储指针再访问成员”的两步,而是等价于连续的链式调用:
(((C().operator->()).operator->()).operator->())->data = 1;
整个赋值语句是一个完整表达式,其中所有临时对象(C()临时实例、B::operator->()返回的B临时实例、A::operator->()返回的A临时实例)都会在整个赋值操作完成后才被销毁。因此,访问data并赋值的操作是在A临时对象存活期间进行的,完全合法。
需要注意的是:如果你把operator->()返回的指针存储到一个持久变量中,后续再通过该指针访问成员,此时临时对象已经销毁,就会触发悬垂指针的未定义行为——但这属于使用方式的问题,和operator->()的链式调用规则无关。
内容的提问来源于stack exchange,提问作者Die4Toast
相关产品推荐
相关产品推荐

