C++类成员赋值与局部资源传递的有效性及未定义行为问询
C++变量生命周期与类成员操作的有效性解答
示例1:局部变量设置类成员的有效性问题
问题回顾
class Test { public: Test(){m_x = 0;}; ~Test() {}; void setX(const int x) {m_x=x;} int getX() const {return m_x;} private: int m_x; }; void SetX(Test& test) { int x = 2; test.setX(x); } int main() { Test X; SetX(X); std::cout << "XX: " << X.getX() << std::endl; return 0; }
提问:通过上述方式设置类成员变量是否有效?当局部变量x超出作用域后是否会出现随机行为?
解答
这种方式完全有效,局部变量x销毁后不会产生任何随机行为,核心原因在于参数传递的方式:
setX的参数是const int x,属于值传递——调用test.setX(x)时,程序会把局部变量x的数值(也就是2)拷贝一份传给函数参数,两者是完全独立的内存空间。setX内部只是把这份拷贝的数值赋值给Test类的成员m_x,完成赋值后,m_x就独立持有了这个值,和原来的局部变量x没有任何关联。- 当
SetX执行完毕,局部变量x超出作用域被销毁时,Test对象X的m_x已经保存了拷贝后的数值2,不会受到任何影响。程序运行后会正常输出XX: 2。
示例2:局部资源传递给类构造函数的有效性问题
问题回顾
class Test { public: Test(){m_x = 0;}; ~Test() {}; void init(const int x, const int y) { AnotherClassRessource res(x,y); m_other.reset(new AnotherClass(res)); } void doSomething() { m_other->doSomething(); } private: int m_x; std::unique_ptr<AnotherClass> m_other; }; int main() { Test X; X.init(1,2); X.doSomething(); return 0; }
提问:在init函数中创建局部AnotherClassRessource并传递给AnotherClass构造函数的操作是否有效?是否会产生未定义行为?该结果是否取决于AnotherClass内部是否持有res的引用或指针?
解答
这个操作的有效性和是否产生未定义行为,完全取决于AnotherClass的构造函数如何处理传入的res对象,分两种情况分析:
如果
AnotherClass构造函数是值传递/拷贝res的内容
比如AnotherClass的构造函数内部把res的x、y值复制到自己的成员变量中,或者直接以值的形式接收res(即AnotherClass(AnotherClassRessource res)),那么这个操作是完全有效的:- 局部变量
res在传递给构造函数时会被拷贝一份,AnotherClass对象持有的是这份独立的拷贝,和原局部res没有关联。 - 当
init执行完毕,res销毁后,m_other指向的AnotherClass对象内部已经保存了自己的拷贝,调用doSomething()不会有任何问题,也不会产生未定义行为。
- 局部变量
如果
AnotherClass构造函数保存了res的指针或引用
比如AnotherClass的成员变量是AnotherClassRessource& m_res或者AnotherClassRessource* m_res,并且在构造函数中把传入的res的引用/指针赋值给这些成员,那情况就完全不同了:- 局部变量
res是init函数的栈变量,当init执行完毕,res会被销毁,其占用的栈内存会被回收。 - 此时
AnotherClass对象持有的引用/指针就变成了悬空引用/悬空指针,后续调用doSomething()时,访问这个悬空的引用/指针会触发未定义行为——程序可能崩溃、输出异常结果,甚至看似正常运行但存在严重的内存安全隐患,具体行为完全不可预测。
- 局部变量
内容的提问来源于stack exchange,提问作者LonelyDriver
相关产品推荐
相关产品推荐

