C++构造函数内销毁无效对象的正确实现方式
在C++中处理无效对象的正确方式
首先看你提供的DateTimes类代码:
#include <math.h> using namespace std; class DateTimes { private: int month; int day; float startTime; float endTime; bool checkValid() { if(month<1 or month>12) { return false; } if(day<1 or day>7) { return false; } if(startTime-floor(startTime)>59) { return false; } if(endTime-floor(endTime)>59) { return false; } return true; } public: DateTimes() { } DateTimes(int monthy,int dayy,float startTimey,float endTimey) { month = monthy; day = dayy; startTime = startTimey; endTime = endTimey; if(!checkValid()) { } } ~DateTimes() { } };
你想在checkValid()返回false时销毁当前对象,但直接调用this.~DateTimes()是错误的——构造函数执行过程中,对象还处于初始化阶段,手动调用析构函数会导致后续系统自动调用析构时出现双重销毁,属于未定义行为,编译器也会禁止这种操作。
下面是两种合法且符合C++规范的实现方式:
方式一:使用工厂函数创建对象
把构造函数设为私有,通过静态工厂函数完成参数验证,验证失败则不返回有效对象。这种方式更安全,用户无法直接创建无效对象。
修改后的代码:
#include <math.h> #include <optional> using namespace std; class DateTimes { private: int month; int day; float startTime; float endTime; // 私有构造函数,仅内部调用 DateTimes(int monthy, int dayy, float startTimey, float endTimey) : month(monthy), day(dayy), startTime(startTimey), endTime(endTimey) {} bool checkValid() const { if(month < 1 || month > 12) return false; if(day < 1 || day > 7) return false; // 原代码判断逻辑有误,小数部分代表分钟的话,应判断是否>0.59(比如13.45是13点45分,小数部分0.45) if(startTime - floor(startTime) > 0.59f) return false; if(endTime - floor(endTime) > 0.59f) return false; return true; } public: // 静态工厂函数,返回optional类型,验证失败返回空 static optional<DateTimes> create(int month, int day, float startTime, float endTime) { DateTimes temp(month, day, startTime, endTime); if(temp.checkValid()) return temp; return nullopt; } // 按需添加其他成员函数 };
使用示例:
// 创建对象,验证失败则dt为空 auto dt = DateTimes::create(13, 5, 10.30, 12.45); if(dt) { // 操作有效对象 } else { // 处理参数无效的情况 }
方式二:构造函数抛出异常
在构造函数中验证失败时抛出异常,此时编译器会自动清理已构造的成员变量,不会生成完整的对象,避免无效对象存在。
修改后的代码:
#include <math.h> #include <stdexcept> using namespace std; class DateTimes { private: int month; int day; float startTime; float endTime; bool checkValid() const { if(month < 1 || month > 12) return false; if(day < 1 || day > 7) return false; if(startTime - floor(startTime) > 0.59f) return false; if(endTime - floor(endTime) > 0.59f) return false; return true; } public: DateTimes() = default; DateTimes(int monthy, int dayy, float startTimey, float endTimey) : month(monthy), day(dayy), startTime(startTimey), endTime(endTimey) { if(!checkValid()) { throw invalid_argument("Invalid date or time parameters"); } } // 按需添加其他成员函数 };
使用示例:
try { DateTimes dt(13, 5, 10.30, 12.45); // 操作有效对象 } catch(const invalid_argument& e) { // 捕获异常,处理无效参数 cout << "Error: " << e.what() << endl; }
额外提示
用float存储时间存在精度问题(比如12.30可能被存储为近似值12.299999),建议改用int存储总分钟数,或者使用C++标准库的std::chrono系列类型来处理时间,避免精度误差导致的验证错误。
内容的提问来源于stack exchange,提问作者Root Groves
相关产品推荐
相关产品推荐

