You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用智能指针与vector构建默克尔树时持续崩溃的问题

默克尔树构建代码的问题分析与修复

核心问题排查

你的代码触发0xC0000005(空指针访问)错误,同时存在死循环、内存双重释放问题,具体原因如下:

1. 初始vector初始化错误

std::vector< std::shared_ptr<merkle::MerkleNode> > nodes(values.size());

这行代码创建了包含values.size()个空shared_ptr的vector,后续push_back添加有效节点后,vector前半部分全是空指针。循环中从nodes.begin()开始访问时,第一个元素就是空指针,调用(*it)->hash()直接触发空指针解引用崩溃。

2. 死循环问题

while (nodes.size() > 1)循环内未将nodes更新为新生成的new_nodes,导致nodes.size()永远不会减小,陷入无限循环。

3. 返回值的内存错误

return std::move(std::shared_ptr<MerkleNode>(nodes[0].get()));

用get()获取原始指针构造新shared_ptr,会让两个shared_ptr管理同一块内存,最终触发双重释放。

修复后的代码

#include <vector>
#include <memory>
#include <string>

namespace merkle {
struct MerkleNode {
    std::string hash_;
    std::shared_ptr<MerkleNode> left_;
    std::shared_ptr<MerkleNode> right_;

    // 叶子节点构造函数
    MerkleNode(const std::string& value) : hash_(value), left_(nullptr), right_(nullptr) {}
    // 中间节点构造函数
    MerkleNode(std::shared_ptr<MerkleNode> left, std::shared_ptr<MerkleNode> right)
        : left_(std::move(left)), right_(std::move(right)) {
        // 此处需替换为实际哈希逻辑,示例仅做字符串拼接
        hash_ = left_->hash() + right_->hash();
    }

    const std::string& hash() const { return hash_; }
};
} // namespace merkle

inline std::shared_ptr<merkle::MerkleNode> AddLeaf(const std::string &vleft, const std::string &vright) {
    auto left = std::make_shared<merkle::MerkleNode>(vleft);
    auto right = std::make_shared<merkle::MerkleNode>(vright);
    return std::make_shared<merkle::MerkleNode>(std::move(left), std::move(right));
}

std::shared_ptr<merkle::MerkleNode> Build(const std::vector<std::string> &values) {
    if (values.empty()) {
        return nullptr;
    }

    // 初始化空vector,避免空指针占位
    std::vector<std::shared_ptr<merkle::MerkleNode>> nodes;
    nodes.reserve(values.size());
    for (const auto &value : values) {
        nodes.push_back(std::make_shared<merkle::MerkleNode>(value));
    }

    while (nodes.size() > 1) {
        // 奇数节点数时复制最后一个节点凑偶数
        if (nodes.size() % 2 != 0) {
            nodes.push_back(nodes.back());
        }

        std::vector<std::shared_ptr<merkle::MerkleNode>> new_nodes;
        new_nodes.reserve(nodes.size() / 2);

        // 用索引遍历更直观,避免迭代器移动的潜在问题
        for (size_t i = 0; i < nodes.size(); i += 2) {
            auto parent = std::make_shared<merkle::MerkleNode>(nodes[i], nodes[i+1]);
            new_nodes.push_back(std::move(parent));
        }

        // 更新节点层,推进循环
        nodes.swap(new_nodes);
    }

    // 直接返回根节点,无需额外构造shared_ptr
    return nodes[0];
}

额外优化点

  • 用reserve()提前分配vector内存,减少扩容开销
  • 替换迭代器为索引遍历,降低操作复杂度
  • 补充MerkleNode结构体定义(适配修复逻辑)
  • 增加空输入的边界处理

内容的提问来源于stack exchange,提问作者Mauricio Alvarez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:25:32