oneTBB concurrent_vector 非成员二元比较运算(operator== / operator!=)规范与源码实现解析
2026/9/14 16:04:36 网站建设 项目流程

oneTBB concurrent_vector 非成员二元比较运算(operator== / operator!=)规范与源码实现解析

【免费下载链接】moldmold: A Modern Linker 🦠项目地址: https://gitcode.com/GitHub_Trending/mo/mold

本文围绕 oneTBB 规范文档中的 “Non-member binary comparisons” 一节展开,讲解concurrent_vector容器两个非成员比较运算符(operator==operator!=)的相等性语义、函数签名与返回值约定,并结合当前仓库中 oneTBB 的实际头文件实现(std::equal逐元素比对、C++20 三路比较的条件编译分支)说明其底层行为与适用前提,帮助读者在多线程并行容器场景下正确、高效地使用这些比较接口。

1. 文档定位:concurrent_vector 规范中的比较运算一节

在当前仓库中,oneTBB 的规范文档按容器成员拆分为多个 RST 小节。本主题对应 non_member_binary_comparisons.rst,与同目录下的 non_member_lexicographical_comparisons.rst(字典序比较operator<等)、non_member_swap.rst(swap非成员函数)等章节共同构成concurrent_vector的完整非成员接口规范。

concurrent_vector本身是 oneTBB 提供的可多线程并发追加元素的向量容器,其元素访问、扩容与并发语义可参见同目录的 iterators.rst、concurrent_growth.rst 等规范小节。本节讨论的二元比较运算正是建立在这套迭代器与容量语义之上的“容器级整体比较”。

2. 相等性语义:两个 concurrent_vector 何时相等

规范文档给出的相等性定义是逐位置(element-wise)的,两个concurrent_vector对象相等当且仅当同时满足两个条件:

  • 它们包含相同数量的元素(an equal number of elements);
  • 相同位置上的元素两两相等(the elements on the same positions are equal)。

这与std::vector的相等语义完全一致,即“同长度 + 逐元素等价”,而不是比较底层内存布局、容量(capacity)或分配器状态。也就是说,即便两个向量分别由不同分配器配置创建、内部扩容历史不同,只要size()相同且按下标 0..n-1 逐元素==成立,二者在比较运算符视角下就是相等的。

3. 函数签名与返回值约定

规范文档为两个运算符给出的完整签名与返回值说明如下:

3.1 operator==

template <typename T, typename Allocator> bool operator==( const concurrent_vector<T, Allocator>& lhs, const concurrent_vector<T, Allocator>& rhs );

Returns: 若lhs等于rhs(按第 2 节的相等性定义)返回true,否则返回false

3.2 operator!=

template <typename T, typename Allocator> bool operator!=( const concurrent_vector<T, Allocator>& lhs, const concurrent_vector<T, Allocator>& rhs );

Returns: 若lhs不等于rhs返回true,否则返回false

两个运算符均为非成员函数模板,参数以const左值引用传入,不修改任何操作数。由于比较只依赖size()与迭代器遍历,因此对const容器对象调用同样成立——这一点可由实现中使用的begin()/end()const重载保证(见第 4 节)。

4. 源码级实现:size 短路 + std::equal 逐元素比对

规范签名在仓库中的实际实现位于 concurrent_vector.h(旧命名空间头文件 include/tbb/concurrent_vector.h 仅是一行转发到该 oneapi 头文件)。核心实现为:

template <typename T, typename Allocator> bool operator==(const concurrent_vector<T, Allocator> &lhs, const concurrent_vector<T, Allocator> &rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); }

从这段实现可以读出几个关键行为:

  1. 长度先行短路:先用lhs.size() == rhs.size()做前置判断,长度不等时直接返回false,不进入任何元素访问。这是对规范第 2 节第一条“元素数量相等”的直接落地,也意味着不等长的比较开销为 O(1)。
  2. std::equal 完成逐元素比较:长度相等时调用std::equal[begin, end)区间遍历lhs,与rhsbegin()起对应元素逐一==。复杂度为 O(n),其中 n 为共同长度。注意这里没有做“同对象快速返回”之类的特判,比较两个完全相同的局部变量也会走完整遍历。
  3. const 语义天然满足operator==内部使用lhs.begin()/rhs.begin(),而concurrent_vectorbegin()/end()提供了const重载(返回const_iterator,见 concurrent_vector.h),因此对const concurrent_vector对象比较可以正常编译。

operator!=的实现则是纯粹的取反(concurrent_vector.h):

#if !__TBB_CPP20_COMPARISONS_PRESENT template <typename T, typename Allocator> bool operator!=(const concurrent_vector<T, Allocator> &lhs, const concurrent_vector<T, Allocator> &rhs) { return !(lhs == rhs); } #endif // !__TBB_CPP20_COMPARISONS_PRESENT

规范中“trueiflhsis not equal torhs”的返回约定由此得到保证:operator!=operator==的结果严格互补,不存在第三态。

5. 一个值得注意的实现细节:C++20 下的条件编译分支

上面的operator!=#if !__TBB_CPP20_COMPARISONS_PRESENT包裹——在 C++20 比较运算符可用(即编译器支持<=>相关语义)时,oneTBB不再手写operator!=,而是依赖标准库从operator<=>合成的operator!=。对应的三路比较运算符定义紧随其后(concurrent_vector.h):

#if __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONCEPTS_PRESENT template <typename T, typename Allocator> tbb::detail::synthesized_three_way_result<typename concurrent_vector<T, Allocator>::value_type> operator<=>(const concurrent_vector<T, Allocator> &lhs, const concurrent_vector<T, Allocator> &rhs) { return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), tbb::detail::synthesized_three_way_comparator{}); }

这说明两点适用前提:

  • 在使用 C++20 及以上特性编译时,operator<operator>operator<=operator>=operator!=等均由operator<=>派生,比较走字典序(lexicographical)三向比较路径;
  • 在旧标准模式下,则回退到规范文档描述的显式operator==/operator!=二元比较路径。

无论哪条路径,“相等”的最终判定口径都与规范一致:长度相同且逐元素相等。读者在实际工程中应留意自己项目的 C++ 标准版本,以判断实际生效的是哪组运算符。

6. 相邻概念辨析:容器比较 vs 迭代器比较

阅读源码时容易与另一个operator==混淆的是迭代器级的相等比较(concurrent_vector.h):

template <typename Vector, typename T, typename U> bool operator==( const vector_iterator<Vector, T>& i, const vector_iterator<Vector, U>& j ) { return i.my_vector == j.my_vector && i.my_index == j.my_index; }

两者的区别必须分清:

维度容器级operator==迭代器级operator==
比较对象两个concurrent_vector的整体内容两个迭代器的指向
判定条件size()相等且逐元素==指向同一容器对象且下标(index)相同
时间复杂度O(n)(长度不等时 O(1) 短路)O(1)
用途验证两个容器是否携带相同数据循环终止条件(it != vec.end()

特别地,concurrent_vector的迭代器比较检查my_vector(容器指针)是否相同,即只有同一容器内的两个迭代器才可能相等;跨容器的迭代器比较结果为false。这与容器级比较“跨对象比较内容”的语义形成鲜明对照。

7. 实战用法示例

结合规范语义与上述实现,典型用法如下:

#include <oneapi/tbb/concurrent_vector.h> #include <cstdint> int main() { tbb::concurrent_vector<int> a, b; a.reserve(4); b.reserve(4); for (int i = 0; i < 4; ++i) { a.push_back(i); // 顺序追加 b.push_back(i * 2); // 不同内容 } tbb::concurrent_vector<int> c(a.begin(), a.end()); // 区间构造副本 bool same_ac = (a == c); // true:同长度且逐元素相等 bool diff_ab = (a != b); // true:逐元素不等 a.push_back(99); // 长度变为 5,内容仍含 b 没有的差异 bool diff_len = (a != c); // true a.erase(a.end() - 1); // 回到 4 个元素 bool same_again = (a == c); // true }

由实现可确认的行为要点:

  • 比较是只读操作,不要求容器处于空闲状态;规范未对比较期间的并发写入做额外同步承诺,因此在多线程追加元素的窗口期调用比较,结果应理解为某一次可见长度下的一致快照读取(具体可见性行为建议以 concurrent_growth.rst 中的并发语义为准)。
  • 若只想判断“是否为同一对象”或“是否为空”,不要依赖==:长度不等时 O(1) 短路很快,但空容器之间比较仍会直接走长度判断返回true,成本很低;真正昂贵的是等长容器间的 O(n) 全遍历。
  • 元素类型T必须自身支持operator==std::equal的要求);若使用 C++20 三向比较路径,则元素还需要支持<=>合成比较,否则operator<=>不可用。

8. 参考路径汇总

内容路径
规范原文(本节主题)non_member_binary_comparisons.rst
实现头文件(operator== / operator!= / operator<=>)oneapi/tbb/concurrent_vector.h
旧命名空间转发头文件include/tbb/concurrent_vector.h
迭代器实现(含迭代器 operator==)oneapi/tbb/concurrent_vector.h
关联规范:字典序比较non_member_lexicographical_comparisons.rst
关联规范:swap 非成员函数non_member_swap.rst

总结:concurrent_vector的非成员二元比较在规范层面保持了与标准容器一致的“同长度 + 逐元素相等”语义;在实现层面以“长度短路 +std::equal”的朴素而可靠的策略完成,operator!=严格取反operator==,并在 C++20 环境下收敛到operator<=>派生的比较体系。理解这套实现与条件编译分支,可以避免在跨标准版本工程中误判可用运算符,也便于正确评估比较操作的开销。

【免费下载链接】moldmold: A Modern Linker 🦠项目地址: https://gitcode.com/GitHub_Trending/mo/mold

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询