C++代码中移动临时Proxy与临时对象生命周期延长的合法性问询
关于C++移动临时对象与临时生命周期延长的问题
#include <iostream> #include <array> struct Matrix { struct Proxy { Proxy(Matrix& m) : m_ { m } {} Proxy(Proxy&& rhs) : m_ { rhs.m_ }, a { std::move(rhs.a) }, index{rhs.index} {} // 1 Proxy operator[](int i) { ++index; return { std::move(*this) }; } Proxy& operator=(int value) { m_.v = value; return *this; } Matrix& m_; int index = 0; std::array<int, 1000> a; }; Proxy operator[](int index) { return { *this }; } int v = -1; }; int main() { Matrix m; const auto& q = m[1][2][3]; // 2 std::cout << q.index << std::endl; std::cout << q.m_.v << std::endl; }
问题1:代码(1)的移动构造函数用法是否合规,有无未定义行为?
完全符合C++规则,不存在未定义行为风险:
- 移动构造函数
Proxy(Proxy&& rhs)接收右值引用,临时Proxy对象本身就是右值,能合法绑定到右值引用参数,这是C++移动语义的标准用法。 - 移动过程中:
m_是对原Matrix对象的引用,这里只是复制引用别名,而main里的Matrix m生命周期远长于所有临时Proxy,不会出现悬空引用。std::move(rhs.a)是对std::array的移动操作,虽然std::array的移动构造实际是逐元素拷贝(固定大小栈分配容器特性),但完全合法;移动后原rhs.a处于“有效但未指定”状态,但rhs是临时对象,移动后立即销毁,不会再被使用,无风险。
- 移动临时对象是C++标准明确允许的操作,核心就是接管临时对象资源以避免冗余拷贝,这里的用法完全符合设计意图。
问题2:代码(2)中临时对象的生命周期延长是否有保证?
有明确的标准保证,临时对象的生命周期会被延长至引用q的生命周期结束:
- 根据C标准(如C20 §6.7.7),当临时对象被绑定到const左值引用(或右值引用)时,临时对象的生命周期会被延长,直到该引用的生命周期结束。
m[1][2][3]的最终结果是一个临时Proxy对象,它被绑定到const auto& q,因此这个临时对象的生命周期会从“当前全表达式结束”延长到main函数结束(即q销毁时)。- 链式调用中每一步的临时
Proxy会被移动到下一个临时对象,但最终绑定到q的是最后一个临时对象,生命周期延长规则作用于这个最终对象,整个过程安全。
隐藏陷阱检查
这段代码不存在悬空引用或未定义行为:
q.m_绑定的是main中的Matrix m,m的生命周期覆盖q的整个生命周期,引用不会悬空。index是值类型,移动构造时直接拷贝,无引用/指针悬空问题。std::array<int, 1000> a是值类型,移动操作安全,不会导致资源泄漏或悬空。
内容的提问来源于stack exchange,提问作者qloq
相关产品推荐
相关产品推荐

