如何通过移动构造函数将派生对象作为右值引用传入基类指针成员?
问题原因分析
你的段错误根源在于右值引用版本的composite构造函数保存了临时对象的指针。当你传递primitive(10)这类临时对象给该构造函数时,这些临时对象的生命周期仅持续到构造函数执行完毕。构造函数结束后,临时对象被销毁,left和right指针就变成了悬空指针,后续调用evaluate()时访问已释放的内存,触发段错误。
比如composite exp1 = composite(primitive(10), primitive(2), &add);中,primitive(10)和primitive(2)是临时对象,构造函数保存它们的地址后,这两个临时对象立刻被销毁,exp1的left和right指向无效内存。
修复方案
解决这个问题的核心是让composite管理其左右子对象的生命周期,推荐使用智能指针(比如std::unique_ptr)替代裸指针,自动处理对象的创建和销毁,避免悬空指针。
以下是修复后的完整代码:
#include <iostream> #include <memory> // 引入智能指针头文件 using namespace std; typedef int (*operation)(int, int); int add(int a, int b){ return a + b; } int subtract(int a, int b){ return a - b; } class base_object{ public: virtual int evaluate() = 0; virtual ~base_object(){} }; class primitive: public base_object{ private: int value; public: primitive(int _value): value(_value){} // 默认移动构造足够,无需手动实现 int evaluate() override{ return value; } }; class composite: public base_object{ private: // 使用unique_ptr管理子对象所有权 unique_ptr<base_object> left; unique_ptr<base_object> right; operation op; public: explicit composite() = delete; // 接受unique_ptr的右值,转移所有权 composite(unique_ptr<base_object>&& _left, unique_ptr<base_object>&& _right, operation _op): left(move(_left)), right(move(_right)), op(_op){ cout<<"composite moving constructor was called"<<endl; } // 兼容原始指针版本(可选,建议优先用智能指针) composite(base_object* _left, base_object* _right, operation _op): left(_left), right(_right), op(_op){} int evaluate() override{ return op(left->evaluate(), right->evaluate()); } }; int main(){//calculate expression ((10+2)-5) // 使用make_unique创建primitive,转移所有权给composite composite exp1 = composite(make_unique<primitive>(10), make_unique<primitive>(2), &add); composite exp2 = composite(make_unique<composite>(move(exp1)), make_unique<primitive>(5), &subtract); int result = exp2.evaluate(); cout<<"final result of expression="<<result<<endl; return 0; }
关键修改点
- 将
base_object*替换为std::unique_ptr<base_object>:unique_ptr会自动管理对象的生命周期,当composite被销毁时,其持有的子对象也会被自动销毁,避免内存泄漏和悬空指针。 - 构造函数接受
unique_ptr<base_object>&&:通过std::move转移智能指针的所有权,确保composite拥有子对象的控制权。 - 使用
std::make_unique创建对象:安全地分配内存并创建对象,避免手动管理new和delete。
这样修改后,无论是传递临时对象还是移动已有对象,都能保证指针指向的对象始终有效,不会出现段错误。
内容的提问来源于stack exchange,提问作者hamid
相关产品推荐
相关产品推荐

