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
相关产品推荐
相关产品推荐

