在C++中实现类似类型类的信号过滤器时遭遇段错误
问题分析与修复
你的代码触发段错误的核心原因是悬空指针:
当执行filter1 * filter1 * filter1时,运算顺序是(filter1 * filter1) * filter1。第一个filter1 * filter1会生成一个临时的ProductFilter对象,这个临时对象仅在当前表达式的生命周期内存在。但后续创建的第二个ProductFilter会保存指向该临时对象的指针,当临时对象销毁后,指针变为悬空状态,调用filtered_value时访问非法内存,触发段错误。
此外,operator*的参数是ISignalFilter<T>& other(非const左值引用),临时对象无法合法绑定到这种引用,编译器的隐式转换虽然可能让代码编译通过,但会加剧生命周期问题。
修复方案
改用std::shared_ptr管理多态过滤器对象的生命周期,同时调整运算符参数以支持临时对象:
#include <iostream> #include <memory> using namespace std; template <typename T> class ISignalFilter; template <typename F> class ProductFilter; template <typename T> class ISignalFilter : public std::enable_shared_from_this<ISignalFilter<T>> { public: virtual ~ISignalFilter() = default; // 基类必须有虚析构函数 virtual T filtered_value(const T& value) const { // 改为const成员函数 (void)value; std::cout << "Base case usage of method not allowed"; std::abort(); }; // 修改为返回shared_ptr,参数改为const引用 virtual std::shared_ptr<ISignalFilter<T>> operator*(const ISignalFilter<T>& other) const { return std::make_shared<ProductFilter<T>>(this->shared_from_this(), other.shared_from_this()); } }; template <typename F> class ProductFilter : public ISignalFilter<F> { public: // 接收shared_ptr并存储 ProductFilter(std::shared_ptr<ISignalFilter<F>> a, std::shared_ptr<ISignalFilter<F>> b) : a_(std::move(a)), b_(std::move(b)) {} F filtered_value(const F& value) const override { return b_->filtered_value(a_->filtered_value(value)); } private: std::shared_ptr<ISignalFilter<F>> a_; std::shared_ptr<ISignalFilter<F>> b_; }; template <typename T> class IdentityFilter : public ISignalFilter<T> { public: IdentityFilter() {} T filtered_value(const T& value) const override { return value; } }; int main() { std::cout << "hello world" << std::endl; auto filter1 = std::make_shared<IdentityFilter<double>>(); auto filter2 = *filter1 * *filter1 * *filter1; while (true) { double value; std::cout << "input:"; std::cin >> value; std::cout << "filtered: " << filter1->filtered_value(value) << std::endl; std::cout << "filtered: " << filter2->filtered_value(value) << std::endl; std::cout << "The two values above should be always equal." << std::endl; } }
关键修改点
- 添加虚析构函数:基类
ISignalFilter增加虚析构函数,确保通过智能指针销毁派生类对象时能正确调用析构函数。 - 使用
std::shared_ptr管理生命周期:所有过滤器对象通过shared_ptr持有,避免悬空指针,确保对象在被引用时不会被销毁。 - 调整
operator*:- 参数改为
const ISignalFilter<T>& other,允许临时对象绑定; - 返回值改为
shared_ptr<ISignalFilter<T>>,确保返回的过滤器对象生命周期由智能指针管理。
- 参数改为
enable_shared_from_this:让基类继承enable_shared_from_this,方便从当前对象获取对应的shared_ptr,避免手动创建shared_ptr导致的重复析构问题。
内容的提问来源于stack exchange,提问作者Brian Yeh
相关产品推荐
相关产品推荐

