C++类成员指针指向局部变量引发值异常问题求助
问题排查与修复
问题现象
创建Screen对象并初始化Diagonal的length成员后,首次直接访问screen->diagonal->length输出162,但调用get_length()方法后,length值变为32759,后续访问也保持异常值,预期三次输出均为162。尝试改写get_length()方法(使用指针等方式),问题仍未解决。
相关代码
Screen.h
#include "Diagonal/Diagonal.h" class Screen { public: Screen(const unsigned short _height) { // Constructor for diagonal initializing Diagonal diagonal{_height}; this->diagonal = &diagonal; } Diagonal* diagonal{}; // Diagonal declaration private: };
Diagonal.h
struct Diagonal { public: Diagonal() = default; // Default constructor Diagonal(const unsigned short _length) // Length initializing constructor : length{ _length } {} unsigned short get_length() const { // Get value of length return length; } const unsigned short length; // Screen length private: };
Main.cpp
#include <iostream> #include "../Core/Headers/Screen/Screen.h" #include <windows.h> int main() { system("mode con cols=80 lines=162"); // Setting up the terminal's cols and lines MoveWindow(GetConsoleWindow(), 0, 0, 1400, 1000, true); // Setting up the terminal position when starts Screen* screen = new Screen{162}; std::cout << screen->diagonal->length << std::endl; std::cout << screen->diagonal->get_length() << std::endl; std::cout << screen->diagonal->length << std::endl; delete screen; }
问题根源
Screen构造函数中创建的Diagonal diagonal{_height}是局部变量,当构造函数执行完毕后,该局部变量会被销毁,其占用的内存会被系统回收或重新分配。此时screen->diagonal保存的是一个指向已销毁对象的指针(野指针),后续对该指针的访问属于未定义行为——第一次输出162只是巧合(内存还没被覆盖),调用get_length()后内存被改写,就出现了异常值。
修复方案
有两种常见的修复方式:
方案1:将Diagonal作为Screen的成员对象(推荐)
不需要使用指针,直接把Diagonal作为Screen的成员,彻底避免野指针问题:
// Screen.h 修改后 #include "Diagonal/Diagonal.h" class Screen { public: Screen(const unsigned short _height) : diagonal{_height} {} Diagonal diagonal; // 改为成员对象,而非指针 private: };
Main.cpp中的访问方式对应调整:
std::cout << screen->diagonal.length << std::endl; std::cout << screen->diagonal.get_length() << std::endl; std::cout << screen->diagonal.length << std::endl;
方案2:动态分配Diagonal对象
如果必须使用指针,可以通过new动态分配内存,确保对象在Screen生命周期内有效:
// Screen.h 修改后 #include "Diagonal/Diagonal.h" class Screen { public: Screen(const unsigned short _height) { this->diagonal = new Diagonal{_height}; } // 添加析构函数释放动态内存,避免内存泄漏 ~Screen() { delete diagonal; } Diagonal* diagonal{}; private: // 禁用拷贝构造和赋值运算符,避免浅拷贝导致的重复释放问题 Screen(const Screen&) = delete; Screen& operator=(const Screen&) = delete; };
两种方案修改后,三次输出都会是预期的162,且不会出现未定义行为。
内容的提问来源于stack exchange,提问作者fzyier
相关产品推荐
相关产品推荐

