You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VS集成Qt中调用类函数触发Debug错误的问题求助

问题描述

在VS集成的Qt应用中,调用基类指针指向的派生类对象的任意函数时程序都会崩溃,弹出Debug错误对话框。例如调用getFile()本应返回字符串,但程序直接崩溃;尝试改用char*替代string时,得到的是垃圾值而非实际数据。

使用基类指针数组notes* allNotes[1000];存储派生类对象,调用如下代码时触发错误:

void dashboard::receiveDisplayImage(int num) {
    string kk = allNotes[num]->getFile();
    img = new image(this);
    img->finallyImageOutput(kk.c_str());
}

单独检查过类的信息存储正常,数组也未越界。此前直接用vector<schoolNotes>和vector<personalNotes>存储对象时程序正常,改用指针后出现崩溃。

相关完整代码如下:

#include<iostream>
#include<string>
#include<vector>
#include<stdlib.h>
#include <fstream>
#include <typeinfo>
using namespace std;
enum p_type { sclN, persN, n };

class notes
{
public:
    notes();
    notes(string title, string date, string t);
    string getFile() { return fp;}
    virtual p_type get_type();

private:
    string title;
    string date;
    string fp;
};

class personalNotes : public notes
{
private:

public:
    personalNotes();
    personalNotes(string title, string date, string t);
};

class schoolNotes : public notes
{
private:
    string category;
    string topicName;
    string subject;
    

public:
    schoolNotes();
    schoolNotes(string Cat, string Topic, string sub, string title, string date, string t);
};

p_type notes::get_type()
{
    if ( typeid(*this) == typeid(schoolNotes))
        return sclN;
    else if ( typeid(*this) == typeid(personalNotes))
        return persN;
    else
    {
        return n;
        //cerr << "\nNo such  type"; exit(1);
    }

}

notes::notes(string Title, string Date, string t) :title(Title), date(Date), fp(t)
{

}

personalNotes::personalNotes(string title, string date, string t) :notes(title, date, t) {

}

class dashboard
{

public:
    dashboard();

    string tf;
    void addPersonalNote(string title, string date);
    int rownumber;
    void submitFile();
    void writeToFile();
    notes* allNotes[1000];
};

void dashboard::writeToFile() {

    int size;
    ofstream ouf;
    p_type ptype;
    ouf.open("user.txt", ios::binary | ios::trunc);

    if (!ouf)
    {
        cout << "\nCan't open file\n"; return;
    }
    for (int j = 0; j < rownumber; j++)
    {
        ptype = allNotes[j]->get_type();
        ouf.write((char*)&ptype, sizeof(ptype));
        switch (ptype)
        {
        case sclN: size = sizeof(schoolNotes); break;
        case persN: size = sizeof(personalNotes); break;
        }
        ouf.write((char*)(allNotes[j]), size);
        if (!ouf)
        {
            cout << "\nCan't write to file\n";
            return;
        }
    }
    ouf.close();
}

dashboard::dashboard()
    : rownumber(0)
{
}

void dashboard::addPersonalNote(string title, string date)
{
    personalNotes tempPers(title, date, tf);
    allNotes[rownumber]=&tempPers;
    rownumber++;
}

void dashboard::submitFile() {
    tf = "this is a string";
}
int main()
{
    dashboard d;
    d.submitFile();
    d.addPersonalNote("this is title", "this is date");
    d.writeToFile();
}
解决方案

核心问题:悬挂指针(野指针)

崩溃的直接原因是addPersonalNote函数中创建的tempPers是局部栈对象,函数执行完毕后,该对象会被销毁,内存被回收。此时allNotes[rownumber]存储的是指向已销毁对象的指针,后续调用allNotes[num]->getFile()时,访问的是已经释放的内存,导致未定义行为(崩溃或读取垃圾值)。

修复步骤

1. 改用动态分配对象解决悬挂指针问题

修改addPersonalNote函数,使用new在堆上创建对象,确保对象生命周期不受函数栈帧影响:

void dashboard::addPersonalNote(string title, string date)
{
    // 使用new在堆上创建对象,避免局部对象销毁导致指针失效
    personalNotes* tempPers = new personalNotes(title, date, tf);
    allNotes[rownumber] = tempPers;
    rownumber++;
}

注意:后续需要在适当的时机(如程序退出、dashboard销毁时)遍历allNotes数组,用delete释放每个对象,避免内存泄漏。

2. 修复二进制文件写入的问题

当前writeToFile函数直接将类对象写入二进制文件的方式不可行,因为类中包含std::string成员——std::string内部是指向堆内存的指针,直接写入文件只会存储指针地址,而非实际字符串内容。需要实现序列化逻辑,将字符串的长度和内容分别写入:

给基类notes添加虚函数serialize,派生类重写该函数完成自身的序列化:

class notes
{
public:
    // ... 已有成员 ...
    virtual void serialize(ofstream& ouf) const {
        // 写入title
        size_t len = title.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(title.c_str(), len);
        // 写入date
        len = date.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(date.c_str(), len);
        // 写入fp
        len = fp.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(fp.c_str(), len);
    }
    virtual ~notes() = default; // 虚析构函数,确保派生类析构被正确调用
};

class schoolNotes : public notes
{
public:
    // ... 已有成员 ...
    void serialize(ofstream& ouf) const override {
        notes::serialize(ouf); // 先序列化基类成员
        // 写入schoolNotes特有的成员
        size_t len = category.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(category.c_str(), len);
        
        len = topicName.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(topicName.c_str(), len);
        
        len = subject.size();
        ouf.write((char*)&len, sizeof(len));
        ouf.write(subject.c_str(), len);
    }
};

class personalNotes : public notes
{
public:
    // ... 已有成员 ...
    void serialize(ofstream& ouf) const override {
        notes::serialize(ouf); // 基类成员已足够,无需额外写入
    }
};

然后修改writeToFile函数,调用虚函数完成序列化:

void dashboard::writeToFile() {
    ofstream ouf;
    p_type ptype;
    ouf.open("user.txt", ios::binary | ios::trunc);

    if (!ouf)
    {
        cout << "\nCan't open file\n"; return;
    }
    // 先写入笔记数量,方便后续读取
    ouf.write((char*)&rownumber, sizeof(rownumber));
    
    for (int j = 0; j < rownumber; j++)
    {
        ptype = allNotes[j]->get_type();
        ouf.write((char*)&ptype, sizeof(ptype));
        // 调用虚函数完成序列化
        allNotes[j]->serialize(ouf);
        
        if (!ouf)
        {
            cout << "\nCan't write to file\n";
            return;
        }
    }
    ouf.close();
}

3. 补充析构函数避免内存泄漏

在dashboard的析构函数中释放所有动态分配的对象:

class dashboard
{
public:
    // ... 已有成员 ...
    ~dashboard() {
        for (int j = 0; j < rownumber; j++) {
            delete allNotes[j];
            allNotes[j] = nullptr;
        }
    }
};

额外建议

  • 优先使用std::vector<std::unique_ptr<notes>>替代原始指针数组,智能指针可以自动管理内存,避免手动delete导致的内存泄漏或悬空指针问题。
  • 二进制文件读取时也需要对应实现反序列化逻辑,确保能正确恢复对象的所有成员。

内容的提问来源于stack exchange,提问作者mehreen hossain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 18:15:28