1

I have trouble compiling the following code.

#include <vector>
#include <mutex>


class A
{
public:
  A(){}
private:
  std::mutex a_mutex;
};


int main()
{
   std::vector<A> v;
   A a;
   v.push_back(a);
   return 0;
}

This is the error.

$ g++ test__use_of_deleted_function.cpp
In file included from /usr/include/c++/8/x86_64-redhat-linux/bits/c++allocator.h:33,
                 from /usr/include/c++/8/bits/allocator.h:46,
                 from /usr/include/c++/8/string:41,
                 from test__use_of_delete_function.cpp:1:
/usr/include/c++/8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = A; _Args = {const A&}; _Tp = A]’:
/usr/include/c++/8/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = A; _Args = {const A&}; _Tp = A; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<A>]’
/usr/include/c++/8/bits/stl_vector.h:1079:30:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = A; _Alloc = std::allocator<A>; std::vector<_Tp, _Alloc>::value_type = A]’
test__use_of_delete_function.cpp:19:17:   required from here
/usr/include/c++/8/ext/new_allocator.h:136:4: error: use of deleted function ‘A::A(const A&)’
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test__use_of_delete_function.cpp:6:7: note: ‘A::A(const A&)’ is implicitly deleted because the default definition would be ill-formed:
 class A
       ^
test__use_of_delete_function.cpp:6:7: error: use of deleted function ‘std::mutex::mutex(const std::mutex&)’
In file included from /usr/include/c++/8/mutex:43,
                 from test__use_of_delete_function.cpp:3:
/usr/include/c++/8/bits/std_mutex.h:97:5: note: declared here
     mutex(const mutex&) = delete;
     ^~~~~
In file included from /usr/include/c++/8/vector:62,
                 from test__use_of_delete_function.cpp:2:
/usr/include/c++/8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = A; _Args = {A}]’:
/usr/include/c++/8/bits/stl_uninitialized.h:83:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*; bool _TrivialValueTypes = false]’
/usr/include/c++/8/bits/stl_uninitialized.h:134:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*]’
/usr/include/c++/8/bits/stl_uninitialized.h:289:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*; _Tp = A]’
/usr/include/c++/8/bits/stl_uninitialized.h:311:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = A*; _ForwardIterator = A*; _Allocator = std::allocator<A>]’
/usr/include/c++/8/bits/vector.tcc:447:6:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const A&}; _Tp = A; _Alloc = std::allocator<A>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<A*, std::vector<A> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = A*]’
/usr/include/c++/8/bits/stl_vector.h:1085:4:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = A; _Alloc = std::allocator<A>; std::vector<_Tp, _Alloc>::value_type = A]’
test__use_of_delete_function.cpp:19:17:   required from here
/usr/include/c++/8/bits/stl_construct.h:75:7: error: use of deleted function ‘A::A(A&&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test__use_of_delete_function.cpp:6:7: note: ‘A::A(A&&)’ is implicitly deleted because the default definition would be ill-formed:
 class A
       ^
test__use_of_delete_function.cpp:6:7: error: use of deleted function ‘std::mutex::mutex(const std::mutex&)’
In file included from /usr/include/c++/8/mutex:43,
                 from test__use_of_delete_function.cpp:3:
/usr/include/c++/8/bits/std_mutex.h:97:5: note: declared here
     mutex(const mutex&) = delete;
     ^~~~~
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user180574
  • 5,681
  • 13
  • 53
  • 94
  • 2
    These questions are relevant: https://stackoverflow.com/questions/55003269/stdmutex-as-class-member-and-store-class-obect-to-container, https://stackoverflow.com/questions/29986208/how-should-i-deal-with-mutexes-in-movable-types-in-c – Hari Jun 21 '23 at 04:20
  • if you want to protect instances of A when accessed from different threads, do it outside of A instead. – AndersK Jun 21 '23 at 06:15

2 Answers2

0

Since std::mutex's copy-constructor is deleted, you will need to define an explicit copy constructor for A.

A(const A& other) { ... }

You'll probably want to look at C++'s idiomatic rule of 4 What is the Rule of Four (and a half)?

  • 3
    Note that it might be dangerous to allow `std::vector` to relocate a class object with a mutex in it—other threads would need to take a lock on the whole `std::vector` to avoid having a mutex for an individual element destroyed while they were holding it. – Davis Herring Jun 21 '23 at 03:35
  • 1
    `std::mutex` isn't copyable/movable for a reason, you need to think very carefully before using it in a container that requires copy/move, simply ignoring it in the copy constructor is likely to lead to interesting bugs – Alan Birtles Jun 21 '23 at 06:54
0

std::mutex can neither be copied or moved.

As shown in answers like here and here, the std::mutex member should be used to implement thread safe copy and move operations for that class, while copying and moving other members of that class.

Otherwise, as shown here, one could hold a smart pointer to the class in the vector (std::vector<std::unique_ptr<A>> v; and v.push_back(std::make_unique<A>());). However, in a practical context doing this alone may not be useful enough.

Hari
  • 1,561
  • 4
  • 17
  • 26
  • 3
    If you find other questions that are relevant to a question they should be flagged as duplicates rather than being added as an answer – Alan Birtles Jun 21 '23 at 06:52