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

C++析构函数每次输入后立即调用问题求助

问题:员工对象析构函数提前触发的原因及修复方案

问题描述

学习C++时编写员工数据录入程序,期望所有员工信息输入完成后才调用析构函数打印删除提示,但实际每输入一位员工信息后,析构函数就会立即触发。

核心问题分析

  1. 动态数组创建错误
    employee *a = new employee;仅创建了单个employee对象,而非容纳n个对象的数组。后续循环中a[i]会访问超出内存范围的区域,属于未定义行为。

  2. 临时对象导致提前析构
    循环中a[i] = employee(no, name, position, time);会创建一个临时employee对象,完成赋值后该临时对象会被立即销毁,触发析构函数打印提示,这就是每次输入后出现删除信息的直接原因。

  3. 浅拷贝引发的双重释放风险
    类中包含char*指针成员,但未重载赋值运算符。默认赋值操作会直接拷贝指针地址,导致原对象和临时对象的指针指向同一块内存。临时对象析构时释放了内存,后续原对象析构会再次释放同一块内存,引发程序崩溃。

  4. 其他代码问题

    • 默认构造函数中time;是无效语句,未初始化time成员;
    • setTime方法的条件判断错误:if(a > 0 && a > 150)逻辑矛盾,应为if(a < 0 || a > 150),否则无法正确拦截无效工时。

修复方案及代码示例

方案1:使用setter避免临时对象+修正动态数组

直接通过成员方法为数组中的对象赋值,避免创建临时对象,同时正确初始化动态数组:

#include <iostream>
#include <cstring>
using namespace std;

class employee{
private:
    int no;
    char *name;
    char *position;
    float time;
public:
    employee();
    employee(int a, char *n, char *m, float x);
    ~employee();
    // setter
    void setNo(int);
    void setName(char*);
    void setPos(char*);
    void setTime(float);
    // getter
    int getNo();
    char* getName();
    char* getPos();
    float getTime();
    // 重载赋值运算符,避免浅拷贝
    employee& operator=(const employee& other);
};

// 实现赋值运算符重载
employee& employee::operator=(const employee& other) {
    if (this == &other) return *this; // 防止自赋值

    // 释放当前对象的内存
    delete[] name;
    delete[] position;

    // 分配新内存并拷贝数据
    name = new char[strlen(other.name) + 1];
    strcpy(name, other.name);
    position = new char[strlen(other.position) + 1];
    strcpy(position, other.position);

    no = other.no;
    time = other.time;

    return *this;
}

void employee::setNo(int a){
    no = a;
}
void employee::setName(char* a){
    delete[] name; // 注意用delete[]释放数组
    name = new char[strlen(a) + 1];
    strcpy(name, a);
}

void employee::setPos(char* a){
    delete[] position;
    position = new char[strlen(a) + 1];
    strcpy(position, a);
}

void employee::setTime(float a){
    if(a < 0 || a > 150){ // 修正条件判断
        cout<<"Enter valid time! (The restriction range is between 0 to 150.)"<<endl;
        exit(0);
    }
    else{
        time = a;
    }
}

// getter实现
int employee::getNo(){
    return no;
}
char* employee::getName(){
    return name;
}
char* employee::getPos(){
    return position;
}
float employee::getTime(){
    return time;
}

// 构造函数实现
employee::employee(){
    name = new char[2]; // 至少能存空格和结束符
    position = new char[9]; // "employee"是8个字符+结束符
    no = 0;
    strcpy(name, " ");
    strcpy(position, "employee");
    time = 0.0f; // 初始化time
}
employee::employee(int a, char *n, char *m, float x){
    name = new char[strlen(n) + 1];
    position = new char[strlen(m) + 1];
    no = a;
    strcpy(name, n);
    strcpy(position, m);
    time = x;
}
employee::~employee(){
    cout<<"The object "<<position<<" "<<name<<" is deleted."<<endl;
    delete[] name; // 数组用delete[]释放
    delete[] position;
}

int main(){
    int n;
    cout<<"The number of employees: ";
    cin>>n;

    employee *a = new employee[n]; // 创建n个对象的动态数组
    for(int i = 0; i < n; i++){
        int no;
        float time;
        char name[20], position[10];
        cout<<"Enter No: ";
        cin>>no;
        cout<<"Enter Name: ";
        cin>>name;
        cout<<"Enter Position: ";
        cin>>position;
        cout<<"Enter Time: ";
        cin>>time;

        // 使用setter直接赋值,避免临时对象
        a[i].setNo(no);
        a[i].setName(name);
        a[i].setPos(position);
        a[i].setTime(time);
    }

    // 最后手动释放数组内存,触发所有对象的析构
    delete[] a;
    return 0;
}

方案2:改用std::string简化内存管理(推荐)

C++中使用std::string可以避免手动管理内存,无需担心浅拷贝、内存泄漏或双重释放问题,代码更简洁安全:

#include <iostream>
#include <string>
using namespace std;

class employee{
private:
    int no;
    string name;
    string position;
    float time;
public:
    employee();
    employee(int a, const string& n, const string& m, float x);
    ~employee();
    // setter
    void setNo(int);
    void setName(const string&);
    void setPos(const string&);
    void setTime(float);
    // getter
    int getNo() const;
    const string& getName() const;
    const string& getPos() const;
    float getTime() const;
};

void employee::setNo(int a){
    no = a;
}
void employee::setName(const string& a){
    name = a;
}

void employee::setPos(const string& a){
    position = a;
}

void employee::setTime(float a){
    if(a < 0 || a > 150){
        cout<<"Enter valid time! (The restriction range is between 0 to 150.)"<<endl;
        exit(0);
    }
    else{
        time = a;
    }
}

// getter实现
int employee::getNo() const{
    return no;
}
const string& employee::getName() const{
    return name;
}
const string& employee::getPos() const{
    return position;
}
float employee::getTime() const{
    return time;
}

// 构造函数实现
employee::employee() : no(0), name(" "), position("employee"), time(0.0f) {}
employee::employee(int a, const string& n, const string& m, float x) 
    : no(a), name(n), position(m), time(x) {}

employee::~employee(){
    cout<<"The object "<<position<<" "<<name<<" is deleted."<<endl;
}

int main(){
    int n;
    cout<<"The number of employees: ";
    cin>>n;

    employee *a = new employee[n];
    for(int i = 0; i < n; i++){
        int no;
        float time;
        string name, position;
        cout<<"Enter No: ";
        cin>>no;
        cout<<"Enter Name: ";
        cin>>name;
        cout<<"Enter Position: ";
        cin>>position;
        cout<<"Enter Time: ";
        cin>>time;

        a[i].setNo(no);
        a[i].setName(name);
        a[i].setPos(position);
        a[i].setTime(time);
    }

    delete[] a;
    return 0;
}

说明

  • 方案1保留了原有的char*实现,但修复了所有问题,包括重载赋值运算符、正确创建数组、避免临时对象;
  • 方案2使用std::string彻底消除了手动内存管理的麻烦,代码更简洁,适合C++初学者优先采用;
  • 两种方案中,所有员工对象的析构函数都会在delete[] a;执行时被依次调用,符合“所有输入完成后再触发析构”的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:04:59