Repository: uxlfoundation/oneTBB (C++)

Issue:
A copy of a concurrent bounded queue doesn't preserve the capacity of the original queue object.
# Summary
A copy of a concurrent bounded queue doesn't preserve the capacity of the original queue.

# Version
2021.10.0

# Environment
AlmaLinux 9
gcc 13.1.0

# Observed Behavior
If I set the capacity of an instance of concurrent bounded queue to a specific value and then create a copy of this queue, the capacity of the new object is set to the default value (0x3fffffffffffffff)

# Expected Behavior
I would expect the copied queue to retain the same capacity as the original.

# Steps To Reproduce

The following code can be used to reproduce the issue:

```
#include <iostream>
#include <tbb/concurrent_queue.h>
int main(int ac, char**av) {
    tbb::concurrent_bounded_queue<int> q;
    q.set_capacity(100);
    std::cout << "q capacity = " << q.capacity() << std::endl;
    tbb::concurrent_bounded_queue<int> q2(q);
    std::cout << "q capacity = " << q.capacity() << " q2 capasity = " << q2.capacity() << std::endl;
}
```

It produces the following output:

```
q capacity = 100
q capacity = 100 q2 capasity = 4611686018427387903
```






Fix (patch):
diff --git a/include/oneapi/tbb/concurrent_queue.h b/include/oneapi/tbb/concurrent_queue.h
index cfd5db6a55..c2b7a196ed 100644
--- a/include/oneapi/tbb/concurrent_queue.h
+++ b/include/oneapi/tbb/concurrent_queue.h
@@ -1,5 +1,5 @@
 /*
-    Copyright (c) 2005-2023 Intel Corporation
+    Copyright (c) 2005-2025 Intel Corporation
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -48,7 +48,6 @@ std::pair<bool, ticket_type> internal_try_pop_impl(void* dst, QueueRep& queue, A
 
 // A high-performance thread-safe non-blocking concurrent queue.
 // Multiple threads may each push and pop concurrently.
-// Assignment construction is not allowed.
 template <typename T, typename Allocator = tbb::cache_aligned_allocator<T>>
 class concurrent_queue {
     using allocator_traits_type = tbb::detail::allocator_traits<Allocator>;
@@ -317,7 +316,6 @@ namespace d2 {
 // A high-performance thread-safe blocking concurrent bounded queue.
 // Supports boundedness and blocking semantics.
 // Multiple threads may each push and pop concurrently.
-// Assignment construction is not allowed.
 template <typename T, typename Allocator = tbb::cache_aligned_allocator<T>>
 class concurrent_bounded_queue {
     using allocator_traits_type = tbb::detail::allocator_traits<Allocator>;
@@ -376,12 +374,14 @@ class concurrent_bounded_queue {
     concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a ) :
         concurrent_bounded_queue(a)
     {
+        my_capacity = src.my_capacity;
         my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
     concurrent_bounded_queue( const concurrent_bounded_queue& src ) :
         concurrent_bounded_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
     {
+        my_capacity = src.my_capacity;
         my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
@@ -420,6 +420,7 @@ class concurrent_bounded_queue {
         if (my_queue_representation != other.my_queue_representation) {
             clear();
             my_allocator = other.my_allocator;
+            my_capacity = other.my_capacity;
             my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item);
         }
         return *this;
@@ -435,6 +436,7 @@ class concurrent_bounded_queue {
                 my_queue_representation->assign(*other.my_queue_representation, other.my_allocator, move_construct_item);
                 other.clear();
                 my_allocator = std::move(other.my_allocator);
+                my_capacity = other.my_capacity;
             }
         }
         return *this;
@@ -547,8 +549,10 @@ class concurrent_bounded_queue {
 
 private:
     void internal_swap( concurrent_bounded_queue& src ) {
-        std::swap(my_queue_representation, src.my_queue_representation);
-        std::swap(my_monitors, src.my_monitors);
+        using std::swap;
+        swap(my_queue_representation, src.my_queue_representation);
+        swap(my_capacity, src.my_capacity);
+        swap(my_monitors, src.my_monitors);
     }
 
     static constexpr std::ptrdiff_t infinite_capacity = std::ptrdiff_t(~size_type(0) / 2);