Eigen Sparse LU solver - c++

I am using the Eigen library in C++ for solving sparse linear equations: Ax=b where, A is a square sparse matrix and b is a rectangular sparse matrix. I have multiple instances of the A matrices and each one has multiple right hand sides b. Hence, I want to factorize all the A matrices once and store them followed by solution for each A with each b.
I tried to use the C++ vector for storing all the solvers. This is a sample code I have written:
vector<Eigen::SparseMatrix<double>> A;
//fill in all A matrices
vector<Eigen::SparseLU<Eigen::SparseMatrix<double>>> solver_A;
Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
for (int i=0;i<A.size();i++){
solver.analyzePattern(A[i]);
solver.factorize(A[i]);
solver_A.push_back(solver);
}
//Later, solver_A entries are to be used to solve for various right hand sides
I am using 3.3.7 version of Eigen and compiling in linux with gcc compiler and c++17 standard. I am getting the following compilation error due to the solver_A.push_back(solver) line:
<pre>/usr/include/c++/7/ext/new_allocator.h: In instantiation of ‘<b>void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Args = {const Eigen::SparseLU<Eigen::SparseMatrix<double, 0, int>, Eigen::COLAMDOrdering<int> >&}; _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >]</b>’:
<b>/usr/include/c++/7/bits/alloc_traits.h:475:4:</b> required from ‘<b>static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Args = {const Eigen::SparseLU<Eigen::SparseMatrix<double, 0, int>, Eigen::COLAMDOrdering<int> >&}; _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<Eigen::SparseLU<Eigen::SparseMatrix<double> > >]</b>’
<b>/usr/include/c++/7/bits/stl_vector.h:943:30:</b> required from ‘<b>void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::SparseLU<Eigen::SparseMatrix<double> > >; std::vector<_Tp, _Alloc>::value_type = Eigen::SparseLU<Eigen::SparseMatrix<double> >]</b>’
<b>header_files/coefficient_computations.cpp:476:51:</b> required from here
<b>/usr/include/c++/7/ext/new_allocator.h:136:4:</b> <font color="#EF2929"><b>error: </b></font>‘Eigen::SparseLU<_MatrixType, _OrderingType>::SparseLU(const Eigen::SparseLU<_MatrixType, _OrderingType>&) [with _MatrixType = Eigen::SparseMatrix<double>; _O<b>rderingType = Eigen::COLAMDOrdering<int>]</b>’ is private within this context
{ <font color="#EF2929"><b>::new((void *)__p) _Up(std::forward<_Args>(__args)...)</b></font>; }
<font color="#EF2929"><b>^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</b></font>
In file included from <b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/SparseLU:44:0</b>,
from <b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/Sparse:31</b>,
from <b>../Eigen_3_3_7/unsupported/Eigen/SparseExtra:13</b>,
from <b>header_files/general_functions.hpp:17</b>,
from <b>header_files/coefficient_computations.hpp:17</b>,
from <b>header_files/coefficient_computations.cpp:2</b>:
<b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/src/SparseLU/SparseLU.h:393:5:</b> <font color="#34E2E2"><b>note: </b></font>declared private here
<font color="#34E2E2"><b>SparseLU</b></font> (const SparseLU& );
<font color="#34E2E2"><b>^~~~~~~~</b></font>
In file included from <b>/usr/include/c++/7/vector:62:0</b>,
from <b>header_files/coefficient_computations.hpp:13</b>,
from <b>header_files/coefficient_computations.cpp:2</b>:
/usr/include/c++/7/bits/stl_construct.h: In instantiation of ‘<b>void std::_Construct(_T1*, _Args&& ...) [with _T1 = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Args = {Eigen::SparseLU<Eigen::SparseMatrix<double, 0, int>, Eigen::COLAMDOrdering<int> >}]</b>’:
<b>/usr/include/c++/7/bits/stl_uninitialized.h:83:18:</b> required from ‘<b>static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Eigen::SparseLU<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::SparseLU<Eigen::SparseMatrix<double> >*; bool _TrivialValueTypes = false]</b>’
<b>/usr/include/c++/7/bits/stl_uninitialized.h:134:15:</b> required from ‘<b>_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Eigen::SparseLU<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::SparseLU<Eigen::SparseMatrix<double> >*]</b>’
<b>/usr/include/c++/7/bits/stl_uninitialized.h:289:37:</b> required from ‘<b>_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Eigen::SparseLU<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::SparseLU<Eigen::SparseMatrix<double> >*; _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >]</b>’
<b>/usr/include/c++/7/bits/stl_uninitialized.h:311:2:</b> required from ‘<b>_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Eigen::SparseLU<Eigen::SparseMatrix<double> >*; _ForwardIterator = Eigen::SparseLU<Eigen::SparseMatrix<double> >*; _Allocator = std::allocator<Eigen::SparseLU<Eigen::SparseMatrix<double> > >]</b>’
<b>/usr/include/c++/7/bits/vector.tcc:426:6:</b> required from ‘<b>void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const Eigen::SparseLU<Eigen::SparseMatrix<double, 0, int>, Eigen::COLAMDOrdering<int> >&}; _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::SparseLU<Eigen::SparseMatrix<double> > >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<Eigen::SparseLU<Eigen::SparseMatrix<double> >*, std::vector<Eigen::SparseLU<Eigen::SparseMatrix<double> > > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Eigen::SparseLU<Eigen::SparseMatrix<double> >*]</b>’
<b>/usr/include/c++/7/bits/stl_vector.h:948:21:</b> required from ‘<b>void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Eigen::SparseLU<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::SparseLU<Eigen::SparseMatrix<double> > >; std::vector<_Tp, _Alloc>::value_type = Eigen::SparseLU<Eigen::SparseMatrix<double> >]</b>’
<b>header_files/coefficient_computations.cpp:476:51:</b> required from here
<b>/usr/include/c++/7/bits/stl_construct.h:75:7:</b> <font color="#EF2929"><b>error: </b></font>‘Eigen::SparseLU<_MatrixType, _OrderingType>::SparseLU(const Eigen::SparseLU<_MatrixType, _OrderingType>&) [with _MatrixType = Eigen::SparseMatrix<double>; _O<b>rderingType = Eigen::COLAMDOrdering<int>]</b>’ is private within this context
{ <font color="#EF2929"><b>::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...)</b></font>; }
<font color="#EF2929"><b>^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</b></font>
In file included from <b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/SparseLU:44:0</b>,
from <b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/Sparse:31</b>,
from <b>../Eigen_3_3_7/unsupported/Eigen/SparseExtra:13</b>,
from <b>header_files/general_functions.hpp:17</b>,
from <b>header_files/coefficient_computations.hpp:17</b>,
from <b>header_files/coefficient_computations.cpp:2</b>:
<b>../Eigen_3_3_7/unsupported/Eigen/../../Eigen/src/SparseLU/SparseLU.h:393:5:</b> <font color="#34E2E2"><b>note: </b></font>declared private here
<font color="#34E2E2"><b>SparseLU</b></font> (const SparseLU& );
<font color="#34E2E2"><b>^~~~~~~~</b></font>
</pre>
The compilation is successful if the line "solver_A.push_back(solver)" is commented. Any help is appreciated either to fix this issue or with alternate solution.

vector::push_back requires the vector elements to be either copy or move constructible. SparseLU is neither of both because it has a private copy constructor (https://eigen.tuxfamily.org/dox/SparseLU_8h_source.html):
private:
// Disable copy constructor
SparseLU (const SparseLU& );
You can work around that in a number of ways. For example, by constructing the vector of solvers with the appropriate size so that it would need not to grow dynamically (https://godbolt.org/z/vS85P8):
vector<Eigen::SparseMatrix<double>> A;
vector<Eigen::SparseLU<Eigen::SparseMatrix<double>>> solver_A(A.size());
for (int i=0;i<A.size();i++) {
solver_A[i].analyzePattern(A[i]);
solver_A[i].factorize(A[i]);
}
If that’s not possible, another option would be to wrap your solvers into a movable type, for example a std::unique_ptr<Eigen::SparseMatrix<double>>.
As a side note, you can use compute instead of analyzePattern and then factorize.

Another possibility is to use std::deque together with the emplace_back method.
Note that the same is not possible with std::vector because here the vector::emplace_back may move the existing elements. deque::emplace_back doesn't need to do this.
I don't know, what algorithm you are implementing but I had a similar problem and thought I needed to store the solvers. In my case it was instead possible to use the solvers one after another (and never again for the same matrix), so I could use one solver instead of a vector. That's probably a better way if it is possible as it is less heavy on memory, as each solver demands 500 bytes on the stack alone.

Related

Eigen: vector of linear system solver

I'm working with the Eigen linear algebra library and need a vector of BiCGSTAB-solvers. Unfortunately, extending this vector is extremely difficult. The minimal (not) working example is
#include <Eigen/Eigen>
int main() {
std::vector< Eigen::BiCGSTAB< Eigen::SparseMatrix< double > > > tmp;
tmp.emplace_back();
}
and yields the error message
$ g++ -I/usr/include/eigen3 main.cpp
In file included from /usr/include/c++/12.2.0/vector:63,
from /usr/include/c++/12.2.0/functional:62,
from /usr/include/eigen3/Eigen/Core:85,
from /usr/include/eigen3/Eigen/Dense:1,
from /usr/include/eigen3/Eigen/Eigen:1,
from main.cpp:1:
/usr/include/c++/12.2.0/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&&]’:
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:182:4: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*]’
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:372:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >]’
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:397:2: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _Allocator = allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >]’
/usr/include/c++/12.2.0/bits/vector.tcc:487:3: required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(iterator, _Args&& ...) [with _Args = {}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; iterator = std::vector<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::iterator]’
/usr/include/c++/12.2.0/bits/vector.tcc:123:21: required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; reference = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&]’
main.cpp:5:21: required from here
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
90 | static_assert(is_constructible<_ValueType, _Tp>::value,
| ^~~~~
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
Trying to std::move is worse, i.e.
#include <Eigen/Eigen>
#include <utility>
int main() {
std::vector< Eigen::BiCGSTAB< Eigen::SparseMatrix< double > > > tmp;
Eigen::BiCGSTAB< Eigen::SparseMatrix< double > > solver;
tmp.push_back( std::move( solver ) );
}
leads to the error message
g++ -I/usr/include/eigen3 main.cpp
In file included from /usr/include/c++/12.2.0/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
from /usr/include/c++/12.2.0/bits/allocator.h:46,
from /usr/include/c++/12.2.0/string:41,
from /usr/include/c++/12.2.0/bits/locale_classes.h:40,
from /usr/include/c++/12.2.0/bits/ios_base.h:41,
from /usr/include/c++/12.2.0/ios:42,
from /usr/include/c++/12.2.0/istream:38,
from /usr/include/c++/12.2.0/sstream:38,
from /usr/include/c++/12.2.0/complex:45,
from /usr/include/eigen3/Eigen/Core:50,
from /usr/include/eigen3/Eigen/Dense:1,
from /usr/include/eigen3/Eigen/Eigen:1,
from main.cpp:1:
/usr/include/c++/12.2.0/bits/new_allocator.h: In instantiation of ‘void std::__new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Args = {Eigen::BiCGSTAB<Eigen::SparseMatrix<double, 0, int>, Eigen::DiagonalPreconditioner<double> >}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >]’:
/usr/include/c++/12.2.0/bits/alloc_traits.h:516:17: required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Args = {Eigen::BiCGSTAB<Eigen::SparseMatrix<double, 0, int>, Eigen::DiagonalPreconditioner<double> >}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; allocator_type = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >]’
/usr/include/c++/12.2.0/bits/vector.tcc:117:30: required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {Eigen::BiCGSTAB<Eigen::SparseMatrix<double, 0, int>, Eigen::DiagonalPreconditioner<double> >}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; reference = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&]’
/usr/include/c++/12.2.0/bits/stl_vector.h:1294:21: required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; value_type = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >]’
main.cpp:9:18: required from here
/usr/include/c++/12.2.0/bits/new_allocator.h:175:11: error: use of deleted function ‘Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >::BiCGSTAB(const Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&)’
175 | { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/eigen3/Eigen/IterativeLinearSolvers:42,
from /usr/include/eigen3/Eigen/Sparse:31,
from /usr/include/eigen3/Eigen/Eigen:2:
/usr/include/eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h:158:7: note: ‘Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >::BiCGSTAB(const Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&)’ is implicitly deleted because the default definition would be ill-formed:
158 | class BiCGSTAB : public IterativeSolverBase<BiCGSTAB<_MatrixType,_Preconditioner> >
| ^~~~~~~~
/usr/include/eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h:158:7: error: use of deleted function ‘Eigen::IterativeSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::IterativeSolverBase(const Eigen::IterativeSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >&)’
In file included from /usr/include/eigen3/Eigen/IterativeLinearSolvers:38:
/usr/include/eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h:143:7: note: ‘Eigen::IterativeSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::IterativeSolverBase(const Eigen::IterativeSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >&)’ is implicitly deleted because the default definition would be ill-formed:
143 | class IterativeSolverBase : public SparseSolverBase<Derived>
| ^~~~~~~~~~~~~~~~~~~
/usr/include/eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h:143:7: error: use of deleted function ‘Eigen::SparseSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::SparseSolverBase(const Eigen::SparseSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >&)’
In file included from /usr/include/eigen3/Eigen/SparseCore:64,
from /usr/include/eigen3/Eigen/Sparse:26:
/usr/include/eigen3/Eigen/src/SparseCore/SparseSolverBase.h:67:7: note: ‘Eigen::SparseSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::SparseSolverBase(const Eigen::SparseSolverBase<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >&)’ is implicitly deleted because the default definition would be ill-formed:
67 | class SparseSolverBase : internal::noncopyable
| ^~~~~~~~~~~~~~~~
/usr/include/eigen3/Eigen/src/SparseCore/SparseSolverBase.h:67:7: error: ‘Eigen::internal::noncopyable::noncopyable(const Eigen::internal::noncopyable&)’ is private within this context
In file included from /usr/include/eigen3/Eigen/Core:162:
/usr/include/eigen3/Eigen/src/Core/util/Meta.h:424:21: note: declared private here
424 | EIGEN_DEVICE_FUNC noncopyable(const noncopyable&);
| ^~~~~~~~~~~
In file included from /usr/include/c++/12.2.0/vector:63,
from /usr/include/c++/12.2.0/functional:62,
from /usr/include/eigen3/Eigen/Core:85:
/usr/include/c++/12.2.0/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&&]’:
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:182:4: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*]’
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:372:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*>; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >]’
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:397:2: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _ForwardIterator = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >*; _Allocator = allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >]’
/usr/include/c++/12.2.0/bits/vector.tcc:487:3: required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(iterator, _Args&& ...) [with _Args = {Eigen::BiCGSTAB<Eigen::SparseMatrix<double, 0, int>, Eigen::DiagonalPreconditioner<double> >}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; iterator = std::vector<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >::iterator]’
/usr/include/c++/12.2.0/bits/vector.tcc:123:21: required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {Eigen::BiCGSTAB<Eigen::SparseMatrix<double, 0, int>, Eigen::DiagonalPreconditioner<double> >}; _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; reference = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >&]’
/usr/include/c++/12.2.0/bits/stl_vector.h:1294:21: required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >; _Alloc = std::allocator<Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > >; value_type = Eigen::BiCGSTAB<Eigen::SparseMatrix<double> >]’
main.cpp:9:18: required from here
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
90 | static_assert(is_constructible<_ValueType, _Tp>::value,
| ^~~~~
/usr/include/c++/12.2.0/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
I'm using Eigen 3.4 and g++ version 12.2.
Any ideas how to fix this?
Turning my comments into a proper answer:
After looking at the code, I found that BiCGSTAB like all solvers inherits from a base class designed to prevent copying, and by extension moving, too: class SparseSolverBase : internal::noncopyable
The exact reasons for this design choice I cannot tell. If I had to guess, I'd say some solvers probably use self-referential attributes (holding pointers to other members) which would break especially with fixed-size matrices. Or using Eigen::Map may cause issues on copy, especially copy-assignment.
std::vector only works with moveable types as it needs to move when it reallocates. Even when calling reserve() beforehand, the code still needs to compile, even if it is never executed.
Three workarounds come to mind:
Use std::deque. It provides a superset of all methods that vector has but its implementation means that as long as you only call emplace_back or emplace_front and not e.g. insert, it does not need moveable types. The downside is that it is a bit slower on all individual accesses
Use std::vector<std::unique_ptr<Solver>>. Less efficient than the deque but now you can also insert, reshuffle, etc.
Use std::unique_ptr<Solver[]> and use the good old new Solver[count] allocation. Starting with C++14, you can use std::make_unique<Solver[]>(count). This has the least overhead, even less than vector but the interface isn't as nice (you can use the [index] operator but the pointer doesn't even know the array size) and the number is fixed after allocation

How to insert elements of Enum type into vector of type uint8_t?

I am very new to C++ programming. I want to insert elements of type enum into a vector<uint8_t> ? ie append all elements of std::vector <ValType> call to std::vector<uint8_t> bravo .Is there any way to do so?
#include <stdio.h>
#include <vector>
#include <cstdint>
enum class ValType : uint8_t
{
Working = 1,
Failed = 0,
Freezed = 0
};
int main()
{
std::vector<uint8_t> bravo = {23, 23, 23, 22, 5};
std::vector<ValType> call;
bravo.insert(bravo.end(), call.begin(), call.end());
return 0;
}
Live Here
I am getting an error while compiling :
In file included from c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\vector:66,
from custom.cpp:2:
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_uninitialized.h: In instantiation of '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _ForwardIterator = unsigned char*]':
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_uninitialized.h:333:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _ForwardIterator = unsigned char*; _Tp = unsigned char]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\vector.tcc:751:34: required from 'void std::vector<_Tp, _Alloc>::_M_range_insert(std::vector<_Tp, _Alloc>::iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_vector.h:1665:19: required from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(std::vector<_Tp, _Alloc>::iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_vector.h:1383:22: required from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::const_iterator, _InputIterator, _InputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; <template-parameter-2-2> = void; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator; std::vector<_Tp, _Alloc>::const_iterator = std::vector<unsigned char>::const_iterator]'
custom.cpp:18:17: required from here
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range
138 | static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
| ^~~~~
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_uninitialized.h:138:72: note: 'std::integral_constant<bool, false>::value' evaluates to false
In file included from c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\vector:60,
from custom.cpp:2:
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h: In instantiation of 'static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = ValType*; _OI = unsigned char*]':
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h:495:30: required from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = ValType*; _OI = unsigned char*]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h:522:42: required from '_OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = false; _II = ValType*; _OI = unsigned char*]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h:530:31: required from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _OI = __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h:620:7: required from '_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _OI = __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\vector.tcc:744:16: required from 'void std::vector<_Tp, _Alloc>::_M_range_insert(std::vector<_Tp, _Alloc>::iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_vector.h:1665:19: required from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(std::vector<_Tp, _Alloc>::iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator]'
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_vector.h:1383:22: required from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::const_iterator, _InputIterator, _InputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<ValType*, std::vector<ValType> >; <template-parameter-2-2> = void; _Tp = unsigned char; _Alloc = std::allocator<unsigned char>; std::vector<_Tp, _Alloc>::iterator = std::vector<unsigned char>::iterator; std::vector<_Tp, _Alloc>::const_iterator = std::vector<unsigned char>::const_iterator]'
custom.cpp:18:17: required from here
c:\program files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\include\c++\11.2.0\bits\stl_algobase.h:385:25: error: cannot convert 'ValType' to 'unsigned char' in assignment
385 | *__result = *__first;
| ~~~~~~~~~~^~~~~~~~~~
Can someone please show me the correct way of doing this?
You can use std::transform with your own conversion function.
std::vector<uint8_t> bravo = {23, 23, 23, 22, 5};
std::vector<ValType> call;
std::transform(bravo.cbegin(), bravo.cend(), std::back_inserter(call),
[](uint8_t a) { return static_cast<ValType>(a); });
This is explained in e.g. this scope enumeration reference:
There are no implicit conversions from the values of a scoped enumerator to integral types, although static_cast may be used to obtain the numeric value of the enumerator.
[Emphasis mine]
So while it might look like inheritance when defining the enumeration, it's not. The type ValType is a completely separate type, which can't be converted to or from any other plain integer type, not even the one used as the enumeration base-type.
That means you can't simply copy from a vector of ValType elements to a vector of uint8_t elements. If you need to do such a copy you must implement your own conversion (using e.g. static_cast), perhaps using std::transform and an back insert iterator.

Accessing object from map causes instantiation of new object C++

I have a big class (call it Collection) and a small class (Item).
Upon initialization of a Collection object it creates a vector of maps to the small objects. The overall structure looks like:
vector<map<int,Item>> storage;
Specifically it looks like:
vector<map<int,Node>> layers;
So when I call a method of Collection to access Item, i.e.
layers[vector_index][map_index].some_method();
it forces Item to be reinitialized. Here's the specific code:
void NN::set_hidden_weights(int hidden_layer_num,int node_index,map<int,double> new_weights){
layers[hidden_layer_num][node_index].set_weights(new_weights); //updates weights
}
What I mean is that I get the following error from my compiler:
g++ -o tests.exe tests.cpp ../src/neural_network.cpp -std=c++11
In file included from /usr/include/c++/4.8/bits/stl_map.h:63:0,
from /usr/include/c++/4.8/map:61,
from ../src/neural_network.cpp:8:
/usr/include/c++/4.8/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {const int&}; long unsigned int ..._Indexes1 = {0ul}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const int; _T2 = Node]’:
/usr/include/c++/4.8/tuple:1079:63: required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {const int&}; _Args2 = {}; _T1 = const int; _T2 = Node]’
/usr/include/c++/4.8/bits/stl_tree.h:140:49: required from ‘std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Val = std::pair<const int, Node>]’
/usr/include/c++/4.8/ext/new_allocator.h:120:4: required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::_Rb_tree_node<std::pair<const int, Node> >; _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const int, Node> >]’
/usr/include/c++/4.8/bits/alloc_traits.h:254:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::_Rb_tree_node<std::pair<const int, Node> >; _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const int, Node> > >; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.8/bits/alloc_traits.h:393:57: required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::_Rb_tree_node<std::pair<const int, Node> >; _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const int, Node> > >; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/include/c++/4.8/bits/stl_tree.h:408:36: required from ‘std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Key = int; _Val = std::pair<const int, Node>; _KeyOfValue = std::_Select1st<std::pair<const int, Node> >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, Node> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const int, Node> >*]’
/usr/include/c++/4.8/bits/stl_tree.h:1669:64: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const int&>, std::tuple<>}; _Key = int; _Val = std::pair<const int, Node>; _KeyOfValue = std::_Select1st<std::pair<const int, Node> >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, Node> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const int, Node> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const int, Node> >]’
/usr/include/c++/4.8/bits/stl_map.h:465:8: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = Node; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, Node> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = Node; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]’
../src/neural_network.cpp:135:27: required from here
/usr/include/c++/4.8/tuple:1090:70: error: no matching function for call to ‘Node::Node()’
second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
^
/usr/include/c++/4.8/tuple:1090:70: note: candidates are:
../src/neural_network.cpp:12:1: note: Node::Node(int, std::vector<int>)
Node::Node(int node_index, vector<int> input_indices){
^
../src/neural_network.cpp:12:1: note: candidate expects 2 arguments, 0 provided
In file included from ../src/neural_network.cpp:9:0:
../src/neural_network.hpp:12:7: note: Node::Node(const Node&)
class Node{
^
../src/neural_network.hpp:12:7: note: candidate expects 1 argument, 0 provided
../src/neural_network.hpp:12:7: note: Node::Node(Node&&)
../src/neural_network.hpp:12:7: note: candidate expects 1 argument, 0 provided
I don't have a default constructor for my Item class nor a copy constructor, and at any rate what I really want to do is manipulate the Item itself, not a copy of it. Does anyone have any recommendations on how to proceed? I'm really confused why I'm getting these initialization errors when the object Item is already created.
Invocation of indexing operator on map layers[hidden_layer_num][node_index] causes a new map to be constructed (if it wasn't there yet) with node_index as key and default constructed value. You should use map::find() to access already present items.

strange error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr when no pointers really created

I have a class, which looks like that:
template<typename T>
using VectorPtr=std::vector<std::unique_ptr<T>>;
template<typename T>
using VectorRawPtr=std::vector<T*>;
class ItemsSet{ // <-- Compiler say this line contans an error 0_o ?
public:
ItemsSet(VectorPtr<Item>& items);
~ItemsSet() = default;
VectorRawPtr<Item> GetItems();
VectorRawPtr<Item> GetSuitableItemsForPeriod(const IPeriod &period);
double CalculateTotal();
private:
VectorPtr<Item> _items;
};
constructor looks like:
ItemsSet::ItemsSet(VectorPtr<Item> & items) {
for(auto &itm: items){
_items.emplace_back(std::move(itm));
}
}
however this code isn't compiled and failed with error:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<Item, std::default_delete<Item> >; _Args = {const std::unique_ptr<Item, std::default_delete<Item> >&}]':
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:75:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*; bool _TrivialValueTypes = false]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:126:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_uninitialized.h:281:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Item, std::default_delete<Item> >*, std::vector<std::unique_ptr<Item, std::default_delete<Item> >, std::allocator<std::unique_ptr<Item, std::default_delete<Item> > > > >; _ForwardIterator = std::unique_ptr<Item, std::default_delete<Item> >*; _Tp = std::unique_ptr<Item, std::default_delete<Item> >]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_vector.h:322:31: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<Item, std::default_delete<Item> >; _Alloc = std::allocator<std::unique_ptr<Item, std::default_delete<Item> > >]'
/cygdrive/d/code/itemSet.h:4:19: required from here
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_construct.h:75:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Item; _Dp = std::default_delete<Item>]'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
Could anyone explain me what I'm doing wrong and how could I fix my problem?
I'm pretty sure that actual problem is an implicit copy constructor ither for ItemsSet or Item. Because you using unique_ptr's which can't really be copied, copy constructor can't be generated properly. Try to explicitly delete copy constructors and find the place where they used and change those place to move declaration for example, or use shared pointers.
This isn't the actual code that produces the error (your line numbers don't match, and neither do the errors; you should present an actual testcase here), but we can still see the problem.
unique_ptrs cannot be copied (they're "unique"!), yet by copy-initialising _items from a whole vector of them, you're attempting to copy them all. You can't do that.
You could move the constructor argument into _items instead.
I don't know if this will fix it or not, but you might try moving the constructor parameter directly into _items instead of moving each individual member into it:
ItemsSet::ItemsSet(VectorPtr<Item>&& items)
: _items(std::move(items))
{
}

How to declare a vector of atomic in C++

I am intending to declare a vector of atomic variables to be used as counters in a multithreaded programme. Here is what I tried:
#include <atomic>
#include <vector>
int main(void)
{
std::vector<std::atomic<int>> v_a;
std::atomic<int> a_i(1);
v_a.push_back(a_i);
return 0;
}
And this is the annoyingly verbose error message of gcc 4.6.3:
In file included from /usr/include/c++/4.6/x86_64-linux-gnu/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.6/bits/allocator.h:48,
from /usr/include/c++/4.6/vector:62,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, const _Tp&) [with _Tp = std::atomic<int>, __gnu_cxx::new_allocator<_Tp>::pointer = std::atomic<int>*]’:
/usr/include/c++/4.6/bits/stl_vector.h:830:6: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/ext/new_allocator.h:108:9: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:538:7: error: declared here
In file included from /usr/include/c++/4.6/vector:70:0,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::atomic<int>&}, _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::atomic<int>*, std::vector<std::atomic<int> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = std::atomic<int>*]’:
/usr/include/c++/4.6/bits/stl_vector.h:834:4: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/bits/vector.tcc:319:4: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:538:7: error: declared here
/usr/include/c++/4.6/bits/stl_vector.h:834:4: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/bits/vector.tcc:319:4: error: use of deleted function ‘std::atomic<int>& std::atomic<int>::operator=(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:539:15: error: declared here
In file included from /usr/include/c++/4.6/x86_64-linux-gnu/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.6/bits/allocator.h:48,
from /usr/include/c++/4.6/vector:62,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, _Args&& ...) [with _Args = {std::atomic<int>}, _Tp = std::atomic<int>, __gnu_cxx::new_allocator<_Tp>::pointer = std::atomic<int>*]’:
/usr/include/c++/4.6/bits/vector.tcc:306:4: instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::atomic<int>&}, _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::atomic<int>*, std::vector<std::atomic<int> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_vector.h:834:4: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/ext/new_allocator.h:114:4: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:538:7: error: declared here
In file included from /usr/include/c++/4.6/vector:61:0,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/bits/stl_algobase.h: In static member function ‘static _BI2 std::__copy_move_backward<true, false, std::random_access_iterator_tag>::__copy_move_b(_BI1, _BI1, _BI2) [with _BI1 = std::atomic<int>*, _BI2 = std::atomic<int>*]’:
/usr/include/c++/4.6/bits/stl_algobase.h:581:18: instantiated from ‘_BI2 std::__copy_move_backward_a(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = std::atomic<int>*, _BI2 = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_algobase.h:590:34: instantiated from ‘_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = std::atomic<int>*, _BI2 = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_algobase.h:661:15: instantiated from ‘_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = std::atomic<int>*, _BI2 = std::atomic<int>*]’
/usr/include/c++/4.6/bits/vector.tcc:313:4: instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::atomic<int>&}, _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::atomic<int>*, std::vector<std::atomic<int> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_vector.h:834:4: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/bits/stl_algobase.h:546:6: error: use of deleted function ‘std::atomic<int>& std::atomic<int>::operator=(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:539:15: error: declared here
In file included from /usr/include/c++/4.6/vector:63:0,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/bits/stl_construct.h: In function ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::atomic<int>, _Args = {std::atomic<int>}]’:
/usr/include/c++/4.6/bits/stl_uninitialized.h:77:3: instantiated from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<std::atomic<int>*>, _ForwardIterator = std::atomic<int>*, bool _TrivialValueTypes = false]’
/usr/include/c++/4.6/bits/stl_uninitialized.h:119:41: instantiated from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<std::atomic<int>*>, _ForwardIterator = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_uninitialized.h:259:63: instantiated from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<std::atomic<int>*>, _ForwardIterator = std::atomic<int>*, _Tp = std::atomic<int>]’
/usr/include/c++/4.6/bits/stl_uninitialized.h:269:24: instantiated from ‘_ForwardIterator std::__uninitialized_move_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = std::atomic<int>*, _ForwardIterator = std::atomic<int>*, _Allocator = std::allocator<std::atomic<int> >]’
/usr/include/c++/4.6/bits/vector.tcc:343:8: instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::atomic<int>&}, _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::atomic<int>*, std::vector<std::atomic<int> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = std::atomic<int>*]’
/usr/include/c++/4.6/bits/stl_vector.h:834:4: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/bits/stl_construct.h:76:7: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:538:7: error: declared here
How do I solve this?
The error disappears when I comment out the line with push_back() .
edit: I edited the post... For those of you who saw the first post, the error was embarrassingly that I used gcc instead of g++ :\
As described in this closely related question that was mentioned in the comments, std::atomic<T> isn't copy-constructible, nor copy-assignable.
Object types that don't have these properties cannot be used as elements of std::vector.
However, it should be possible to create a wrapper around the std::atomic<T> element that is copy-constructible and copy-assignable. It will have to use the load() and store() member functions of std::atomic<T> to provide construction and assignment (this is the idea described by the accepted answer to the question mentioned above):
#include <atomic>
#include <vector>
template <typename T>
struct atomwrapper
{
std::atomic<T> _a;
atomwrapper()
:_a()
{}
atomwrapper(const std::atomic<T> &a)
:_a(a.load())
{}
atomwrapper(const atomwrapper &other)
:_a(other._a.load())
{}
atomwrapper &operator=(const atomwrapper &other)
{
_a.store(other._a.load());
}
};
int main(void)
{
std::vector<atomwrapper<int>> v_a;
std::atomic<int> a_i(1);
v_a.push_back(a_i);
return 0;
}
EDIT: As pointed out correctly by Bo Persson, the copy operation performed by the wrapper is not atomic. It enables you to copy atomic objects, but the copy itself isn't atomic. This means any concurrent access to the atomics must not make use of the copy operation. This implies that operations on the vector itself (e.g. adding or removing elements) must not be performed concurrently.
Example: If, say, one thread modifies the value stored in one of the atomics while another thread adds new elements to the vector, a vector reallocation may occur and the object the first thread modifies may be copied from one place in the vector to another. In that case there would be a data race between the element access performed by the first thread and the copy operation triggered by the second.
To first answer your headline question: you can declare a std::vector<std::atomic<...>> easily, as you have done in your example.
Because of the lack of copy or move constructors for std::atomic<> objects, however, your use of the vector will be restricted as you found out with the compilation error on push_back(). Basically you can't do anything that would invoke either constructor.
This means your vector's size must be fixed at construction, and you should manipulate elements using operator[] or .at(). For your example code, the following works1:
std::vector<std::atomic<int>> v_a(1);
std::atomic<int> a_i(1);
v_a[0] = a_i.load();
If the "fixed size at construction" limitation is too onerous, you can use std::deque instead. This lets you emplace objects, growing the structure dynamically without requiring copy or move constructors, e.g.:
std::deque<std::atomic<int>> d;
d.emplace_back(1);
d.emplace_back(2);
d.pop_back();
There are still some limitations, however. For example, you can pop_back(), but you cannot use the more general erase(). The limitations make sense: an erase() in the middle of the blocks of contiguous storage used by std::deque in general requires the movement of elements, hence requires copy/move constructor or assignment operators to be present.
If you can't live with those limitations, you could create a wrapper class as suggested in other answers but be aware of the underlying implementation: it makes little sense to move a std::atomic<> object once it is being used: it would break any threads concurrently accessing the objects. The only sane use of copy/move constructors is generally in the initial setup of collections of these objects before they are published to other threads.
1 Unless, perhaps, you use Intel's icc compiler, which fails with an internal error while compiling this code.
Looks to me like atomic<T> has no copy constructor. Nor a move constructor, as far as I can tell.
One work around might be to use vector<T>::emplace_back() to construct the atomic in-place in the vector. Alas, I don't have a C++11 compiler on me right now, or I'd go and test it.
As others have properly noted, the cause of the compiler's error is that std::atomic explicitly prohibits the copy constructor.
I had a use case where I wanted the convenience of an STL map (specifically I was using a map of maps in order to achieve a sparse 2-dimensional matrix of atomics so I can do something like int val = my_map[10][5]). In my case there would be only one instance of this map in the program, so it wouldn't be copied, and even better I can initialize the entire thing using braced initialization. So it was very unfortunate that while my code would never attempt copying individual elements or the map itself, I was prevented from using an STL container.
The workaround I ultimately went with is to store the std::atomic inside a std::shared_ptr. This has pros, but possibly a con:
Pros:
Can store std::atomic inside any STL container
Does not require/restrict using only certain methods of STL containers.
Pro or Con (this aspect's desirability depends on the programs' use cases):
- There is only a single shared atomic for a given element. So copying the shared_ptr or the STL container will still yield a single shared atomic for the element. In other words, if you copy the STL container and modify one of the atomic elements, the other container's corresponding atomic element will also reflect the new value.
In my case the Pro/Con characteristic was moot due to my use case.
Here's a brief syntax to initialize a std::vector with this method:
#include <atomic>
#include <memory>
#include <vector>
std::vector<std::shared_ptr<std::atomic<int> > > vecAtomicInts
{
std::shared_ptr<std::atomic<int> >(new std::atomic<int>(1) ),
std::shared_ptr<std::atomic<int> >(new std::atomic<int>(2) ),
};
// push_back, emplace, etc all supported
vecAtomicInts.push_back(std::shared_ptr<std::atomic<int> >(new std::atomic<int>(3) ) );
// operate atomically on element
vecAtomicInts[1]->exchange(4);
// access random element
int i = *(vecAtomicInts[1]);