使用std::shared_ptr时触发_CrtIsValidHeapPointer断言的问题求助
我尝试在类成员函数中创建并使用std::shared_ptr,该类构造函数接收同一类的私有std::shared_ptr成员,以及通过类对象原始指针(this)创建的std::shared_ptr。每当调用创建该std::shared_ptr的函数foo时,都会触发_CrtIsValidHeapPointer断言。我推测这与shared_ptr的销毁方式有关,但无法查明原因,特求助:是否不允许通过this指针或已有的shared_ptr成员创建新的shared_ptr?
代码示例:
class Containing_Class; class Some_Class { }; class Set_Value_Command { public: Set_Value_Command(std::shared_ptr<Some_Class> ptr1, std::shared_ptr<Containing_Class> ptr2) : _ptr1(ptr1), _ptr2(ptr2) {} private: std::shared_ptr<Some_Class> _ptr1; std::shared_ptr<Containing_Class> _ptr2; }; class Containing_Class { public: Containing_Class(std::shared_ptr<Some_Class> psc) : _psc(psc) {} void foo() { std::shared_ptr<Set_Value_Command> command = std::make_shared<Set_Value_Command>(_psc, std::shared_ptr<Containing_Class>(this)); } private: std::shared_ptr<Some_Class> _psc; };
main函数(调用foo时触发断言):
int main() { std::shared_ptr<Some_Class> some_class = std::make_shared<Some_Class>(); Containing_Class cc(some_class); cc.foo(); }
核心问题在于:绝对不能用栈上对象的this指针直接构造std::shared_ptr。
你的代码里Containing_Class cc(some_class);是在栈上创建的对象,而std::shared_ptr<Containing_Class>(this)会让shared_ptr误以为这个对象是通过堆分配(比如new)出来的。当这个shared_ptr的引用计数归零时,会自动调用delete this释放内存,但栈上的对象根本不允许用delete释放——这直接触发了_CrtIsValidHeapPointer断言,因为你试图释放不属于堆的内存。
另外,哪怕对象是堆分配的,直接用this构造shared_ptr也有问题:多个独立的shared_ptr指向同一个对象时,会各自维护独立的引用计数,最终导致对象被重复释放,同样会引发内存错误。
解决方法
方法1:使用std::enable_shared_from_this(推荐)
让Containing_Class继承std::enable_shared_from_this<Containing_Class>,然后在foo函数中用shared_from_this()代替直接用this构造shared_ptr。这样所有指向该对象的shared_ptr会共享同一个引用计数,避免重复释放的问题。
修改后的Containing_Class代码:
class Containing_Class : public std::enable_shared_from_this<Containing_Class> { public: Containing_Class(std::shared_ptr<Some_Class> psc) : _psc(psc) {} void foo() { std::shared_ptr<Set_Value_Command> command = std::make_shared<Set_Value_Command>(_psc, shared_from_this()); } private: std::shared_ptr<Some_Class> _psc; };
同时需要修改main函数,确保Containing_Class对象被shared_ptr持有(这是shared_from_this()生效的前提):
int main() { std::shared_ptr<Some_Class> some_class = std::make_shared<Some_Class>(); auto cc = std::make_shared<Containing_Class>(some_class); cc->foo(); }
方法2:避免用shared_ptr管理栈对象(仅特殊场景使用)
如果你的业务场景必须在栈上创建Containing_Class,那绝对不能用shared_ptr管理它的生命周期。此时可以考虑传递原始指针(但要严格保证Set_Value_Command使用指针时,Containing_Class对象仍然存活),或者使用std::weak_ptr(但同样需要对象本身被shared_ptr持有,否则意义不大)。这种方式风险较高,不推荐在复杂场景使用。
补充说明
- 通过已有的shared_ptr成员创建新的shared_ptr是完全没问题的,比如你代码里的
_psc传递给Set_Value_Command,shared_ptr的拷贝操作会正确增加引用计数,不会引发任何问题。 - 只有当用this构造shared_ptr时才会出问题,本质是违背了shared_ptr的生命周期管理规则——它只能管理堆分配且未被其他shared_ptr管理的对象(或者通过enable_shared_from_this关联的对象)。
内容的提问来源于stack exchange,提问作者comp1201

