如何在构造函数的function-try-block中访问对象成员?
问题解答
核心结论
在构造函数的function-try-block的catch块中,绝对不能访问对象的任何非静态成员,包括通过this->name的方式——你的判断完全正确,此时对象尚未完成构造,生命周期未开始,访问成员属于未定义行为(UB),可能导致崩溃或不可预料的结果。
合法的解决方案
要在catch块中获取名字这类信息,唯一合法的方式是在初始化对象成员之前,将需要的数据保存到独立于对象的局部变量中。这个局部变量的生命周期不受对象构造失败的影响,可以安全地在catch块中使用。
方案1:拆分构造函数(推荐,适用于所有成员类型)
通过私有构造函数处理实际初始化,外层构造函数负责保存临时数据并捕获异常:
class MyClass { public: MyClass(std::string param_name) { // 提前保存名字到独立临时变量,不受对象构造影响 std::string temp_name = std::move(param_name); try { // 使用placement new在当前对象内存中调用私有构造函数完成初始化 new (this) MyClass(std::move(temp_name), nullptr); } catch (const std::runtime_error& e) { std::cout << temp_name << " " << e.what() << std::endl; throw; // 必须重新抛出:对象未构造完成,不能进入可用状态 } } private: // 私有构造函数:负责实际成员初始化,可能抛出异常 MyClass(std::string name, void*) : name(std::move(name)), someOtherField(WillProbablyThrowSomeException()) {} std::string name; SomeOtherClass someOtherField; };
方案2:函数体内的try块(仅适用于可默认构造的成员)
如果成员类型支持默认构造,可以放弃function-try-block,改用函数体内的普通try块手动初始化成员:
class MyClass { public: MyClass(std::string param_name) { std::string temp_name = std::move(param_name); try { // 手动初始化成员(注意:不适用于const、引用或无默认构造的成员) name = std::move(temp_name); someOtherField = SomeOtherClass(WillProbablyThrowSomeException()); } catch (const std::runtime_error& e) { std::cout << temp_name << " " << e.what() << std::endl; throw; } } private: std::string name; SomeOtherClass someOtherField; // 需支持默认构造 };
关键规则补充
- 构造函数的
function-try-block捕获的是初始化列表或函数体中抛出的异常,此时对象的生命周期并未开始,任何访问非静态成员的操作都是UB。 catch块必须重新抛出异常(显式throw或隐式),否则编译器会自动重新抛出——未完成构造的对象不能被正常使用。
内容的提问来源于stack exchange,提问作者Morse
相关产品推荐
相关产品推荐

