C++中创建新对象意外修改成员变量问题求助
悬垂引用引发未定义行为:Triangle类引用成员的问题
问题根源
你的Triangle类成员v1、v2、v3是引用类型,但构造函数的参数采用传值方式:
Triangle(Vector3 v1, Vector3 v2, Vector3 v3) : v1(v1), v2(v2), v3(v3) { }
当你在main函数中调用Triangle t(Vector3(0,0,0), Vector3(1,0,0), Vector3(0,1,0))时,三个临时Vector3对象会被创建并作为参数传入构造函数。初始化列表中的引用,绑定的是这些临时参数对象,而非你传入的原始临时对象。
构造函数执行完毕后,这些临时参数对象会被立即销毁,此时Triangle的v1、v2、v3就变成了悬垂引用——指向已经被释放的内存空间。
后续调用to_barycentric等成员函数时,访问这些引用属于未定义行为:内存可能被其他操作(比如你标记的返回Vector3语句,会在栈上创建新对象)覆盖,导致看起来v3被意外修改,本质是非法访问内存引发的随机结果。
解决方案
你改成指针后问题解决,本质是调整了对象生命周期的管理,但更稳妥的方案有几种:
- 存储值而非引用/指针
直接将Triangle的成员改为值类型,彻底避免引用/指针的生命周期问题:
class Triangle { public: Vector3 v1, v2, v3; Triangle(Vector3 v1, Vector3 v2, Vector3 v3) : v1(v1), v2(v2), v3(v3) { } // 其他代码保持不变 };
- 构造函数参数用const引用,确保引用对象生命周期更长
如果必须使用引用,构造函数参数改为const引用,同时保证传入的Vector3对象生命周期不短于Triangle对象:
class Triangle { public: const Vector3& v1, &v2, &v3; Triangle(const Vector3& v1, const Vector3& v2, const Vector3& v3) : v1(v1), v2(v2), v3(v3) { } // 其他代码保持不变 }; // main函数中创建持久化对象 int main(void) { Vector3 p0(0,0,0), p1(1,0,0), p2(0,1,0); Triangle t(p0, p1, p2); // 其他代码保持不变 }
- 使用智能指针管理动态对象
如果Vector3对象是动态分配的,用std::shared_ptr<Vector3>来自动管理对象生命周期,避免悬垂问题。
总结
悬垂引用是C++常见陷阱,核心要求是确保引用指向的对象生命周期至少与引用本身一致。你的代码中引用绑定到了构造函数的临时参数,导致构造结束后引用失效,进而引发未定义行为,表现为无逻辑的变量修改。
内容的提问来源于stack exchange,提问作者Kitsuinox
相关产品推荐
相关产品推荐

