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

unique_ptr实现BST编译生成分支代码,如何生成cmov分支无代码?

关于std::unique_ptr与BST分支无代码生成的问题

问题背景

我在实现二叉搜索树(BST)时选择用std::unique_ptr管理子节点所有权,但发现Ubuntu 24.04.1 LTS上的g++-13编译器处理智能指针版本时,会生成分支代码,而非裸指针版本那样用cmov指令实现的分支无代码。尝试用三元运算符引导编译器生成分支无代码,但未生效。基准测试显示,分支代码版本的耗时是分支无代码版本的1.4倍(测试场景:对含200万个节点的树调用200万次),编译使用RelWithDebInfo模式(开启O2优化)。

简化原型代码

#include <memory>
#include <iostream>
struct node {
    int val;
    node* left_child;
    node* right_child;
};

struct smart_node {
    int val;
    std::unique_ptr<smart_node> left_child;
    std::unique_ptr<smart_node> right_child;
};

node*
__attribute__((noinline))
raw(node* root, int key) {
    node* prev = root;
    node* curr = prev -> left_child;
    while (curr != nullptr) {
        prev = curr;
        bool comp = key < (curr -> val);
        curr = comp ? curr -> left_child : curr -> right_child;
    }
    return prev;
}

smart_node*
__attribute__((noinline))
smart(std::unique_ptr<smart_node> root, int key) {
    smart_node* prev = root.get();
    smart_node* curr = prev -> left_child.get();
    while (curr != nullptr) {
        prev = curr;
        bool comp = key < (curr -> val);
        curr = comp ? curr -> left_child.get() : curr -> right_child.get();
    }
    return prev;
}

int main() {
    // Use null instead of a non-degenerative tree to shorten the code
    // I verified this doesn't cause the assembly of the two functions above to mutate
    auto last1 = raw(nullptr, 1);
    auto last2 = smart(std::make_unique<smart_node>(), 1);
    std::cout << last1 -> val << last2 -> val;
}

汇编代码对比

裸指针版本loop汇编

1310:   48 89 c2                mov    %rax,%rdx
    1313:   48 8b 42 10             mov    0x10(%rdx),%rax
    1317:   3b 32                   cmp    (%rdx),%esi
    1319:   48 0f 4c 42 08          cmovl  0x8(%rdx),%rax
    131e:   48 85 c0                test   %rax,%rax
    1321:   75 ed                   jne    1310 <_Z3rawP4nodei+0x20>

智能指针版本loop汇编

1360:   48 8b 50 08             mov    0x8(%rax),%rdx
    1364:   48 85 d2                test   %rdx,%rdx
    1367:   74 10                   je     1379 <_Z5smartSt10unique_ptrI10smart_nodeSt14default_deleteIS0_EEi+0x39>
    1369:   48 89 d0                mov    %rdx,%rax
    136c:   3b 30                   cmp    (%rax),%esi
    136e:   7c f0                   jl     1360 <_Z5smartSt10unique_ptrI10smart_nodeSt14default_deleteIS0_EEi+0x20>
    1370:   48 8b 50 10             mov    0x10(%rax),%rdx
    1374:   48 85 d2                test   %rdx,%rdx
    1377:   75 f0                   jne    1369 <_Z5smartSt10unique_ptrI10smart_nodeSt14default_deleteIS0_EEi+0x29>

核心问题

  • 如何让编译器强制为std::unique_ptr版本生成cmov指令?(拒绝使用汇编,因其不具备可移植性)
  • 若无法实现,为何裸指针与智能指针版本的编译输出会存在这种差异?

内容的提问来源于stack exchange,提问作者cpp is hard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:52:19