C++使用std::shared_ptr触发Debug assertion failure错误求助
问题根因
你的代码触发断言的核心问题有两个:
- 你在栈上创建了父节点对象
Node<int> n,构造函数中直接用裸指针this构造std::shared_ptr时,智能指针会默认持有该指针的销毁权,当引用计数归零时会尝试delete栈内存,这是非法操作,直接触发堆内存校验断言。 - 即使你将父节点改为堆分配,直接用裸指针
this多次构造std::shared_ptr会生成多个独立的引用计数控制块,导致同一块内存被多次释放;同时父子节点互相持有std::shared_ptr会产生循环引用,双方的引用计数永远无法归零,最终内存泄漏。
C#的垃圾回收机制是基于可达性跟踪的,不需要手动管理对象生命周期,也会自动处理循环引用,所以相同逻辑在C#中可以正常运行。
修复方案
你需要做三处核心修改:
- 让
Node类继承std::enable_shared_from_this,安全地从this生成合法的std::shared_ptr,避免多个控制块的问题 - 父节点指针改用
std::weak_ptr存储,打破循环引用 - 所有
Node对象必须通过std::make_shared创建,禁止栈分配Node实例
修复后完整代码
#include <iostream> #include <memory> template<typename T> class Node : public std::enable_shared_from_this<Node<T>> { using NodePtr = std::shared_ptr<Node<T>>; using WeakNodePtr = std::weak_ptr<Node<T>>; private: Node() {} T value{}; WeakNodePtr parent; // 父指针用weak_ptr打破循环引用 NodePtr child; public: Node(const T& value) : value{ value } {} Node(const T& value, NodePtr child) : Node(value) { this->child = child; if (child != nullptr) { // 用shared_from_this安全生成shared_ptr,不会产生新的控制块 child->parent = shared_from_this(); } } const T& Value() const { return value; } T& ValueRef() const { return value; } // 父指针返回时升级为shared_ptr NodePtr Parent() const { return parent.lock(); } NodePtr Child() const { return child; } }; template<typename T> std::ostream& operator<<(std::ostream& stream, const Node<T>& node) { stream << "{" << node.Value() << "}"; return stream; } int main() { // 所有Node对象都用make_shared创建,不能栈分配 auto n = std::make_shared<Node<int>>(5, std::make_shared<Node<int>>(3)); std::cout << *n; return 0; }
额外说明
如果确实需要支持栈分配的节点,建议放弃用std::shared_ptr存储父指针,改用裸指针存储父节点,自己保证父节点生命周期长于子节点即可,不需要引入额外的复杂度。
内容的提问来源于stack exchange,提问作者somenpc323
相关产品推荐
相关产品推荐

