类内嵌容器存储Task对象时自动触发构造、换vector报下标越界的问题求解
问题根源与对应解决方案
问题本质
std::array<Task, 3>作为类成员时,会在List对象初始化阶段自动构造全部3个元素:也就是你写在Task无参构造里的读用户输入、清屏逻辑会被自动调用3次,完全绕过手动写的createTask()流程,不符合“按需创建Task”的预期。- 换成
std::vector时报下标越界的原因:默认构造的std::vector初始存储长度为0,你在createTask()里用listOfTasks[m_vectorsize] = t1的下标方式赋值,本质是访问不存在的内存位置,触发越界报错。 - 核心设计偏差:把“和用户交互获取任务信息”的逻辑直接绑定在Task的构造函数里,导致只要容器初始化元素,就会强制触发整套交互流程,无法做到按需生成对象。
实现方案
方案1:改用std::vector实现可变长任务列表(推荐)
- 拆分Task类的构造职责:编写不带交互逻辑的默认构造函数,仅把类成员初始化为空状态,删除构造函数里的
std::cin读输入、清屏等I/O逻辑。 - 将原构造函数里的交互逻辑迁移到独立成员函数中,比如
initFromUserInput(),专门负责读取任务名称、初始化创建日期、设置默认未完成状态。 - 把List类的成员容器替换为
std::vector<Task> listOfTasks;,删除手动维护的m_vectorsize变量(vector本身会自动跟踪已存储的元素数量)。 - 修改
createTask()逻辑:创建一个空状态的Task对象,调用它的initFromUserInput()填充任务内容,再通过push_back()方法把对象追加到vector末尾,不要使用下标直接赋值。 - 修改
printTasklist()逻辑:以vector实际存储的元素长度为循环边界遍历,不要硬编码固定循环3次的逻辑,避免空元素访问。
方案2:保留定长std::array但实现按需创建元素
- 不要直接存储值类型的Task数组,换成存储Task对象的智能指针,即把List类的成员改为
std::array<std::unique_ptr<Task>, 3> listOfTasks; - 这种存储方式下,数组初始化时只会生成3个空的智能指针对象,不会自动构造Task实例,完全不会触发Task的构造函数。
- 修改
createTask()逻辑:找到数组中第一个为空的智能指针位置,通过std::make_unique<Task>()生成实际的Task对象(此时才触发Task的交互初始化逻辑),赋值到对应位置。 - 修改
printTasklist()逻辑:遍历数组时先判断当前位置的智能指针是否为空,仅当指针有效时调用对应Task的printTask()方法,避免空指针访问崩溃。
内容的提问来源于stack exchange,提问作者Samenergustav
相关产品推荐
相关产品推荐

