Reputation: 1367
When I compile the below code, I get a compilation error:
std::vector<std::unique_ptr<boxIndex>> tmpVec;
for(const auto& it: hrzBoxTmpMap){
for(const auto& it2: hrzBoxVec){
std::copy_if(hrzBoxVec.begin(), hrzBoxVec.end(), tmpVec.begin(), [&](std::unique_ptr<boxIndex>& p)
{
return !(it.second == p->getTop() &&
it.first != p->getLeft() );
});
}
}
The compilation error is:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_algo.h:
> In instantiation of ‘_OIter std::copy_if(_IIter, _IIter, _OIter,
> _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<std::unique_ptr<boxIndex>*, std::vector<std::unique_ptr<boxIndex> > >; _OIter =
> __gnu_cxx::__normal_iterator<std::unique_ptr<boxIndex>*, std::vector<std::unique_ptr<boxIndex> > >; _Predicate =
> smoothHrzIndexing(std::vector<std::unique_ptr<boxIndex>
> >&)::<lambda(std::unique_ptr<boxIndex>&)>]’: test_word_2.cpp:282:5: required from here
> /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_algo.h:990:6:
> error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>&
> std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&)
> [with _Tp = boxIndex; _Dp = std::default_delete<boxIndex>]’ In file
> included from
> /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/memory:86:0,
> from test_word_2.cpp:8: /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/unique_ptr.h:263:19:
> error: declared here
Can someone help me on this?
Upvotes: 7
Views: 3403
Reputation: 1759
There is no direct way of doing this, but you can chain some STL commands to achieve what you want:
std::stable_partition
or std::partition
to split your container in half.std::move
to move the values you want to move to your new vectorvector.erase
to delete the old, invalid unique_ptrIn the end you have a clean source vector (all moved, invalid entries are removed) and a clean target vector.
this can look something like that:
std::vector<std::unique_ptr<int>> source, target;
// ... fill data
auto it = std::stable_partition(begin(source),end(source),[](std::unique_ptr<int> const& val) {
return *val < 3; // your negated condition
});
std::move(it,end(source),std::back_inserter(target));
source.erase(it,end(source));
Upvotes: 3
Reputation: 153955
What you could do is to use std::move_iterator<...>
using, e.g., something like below (this is a SSCCE demonstrating the crucial point:
#include <iostream>
#include <iterator>
#include <vector>
#include <memory>
int main()
{
std::vector<std::unique_ptr<int>> boxVec;
boxVec.emplace_back(new int(1));
boxVec.emplace_back(new int(17));
boxVec.emplace_back(new int(3));
std::vector<std::unique_ptr<int>> tmpVec;
std::copy_if(std::make_move_iterator(boxVec.begin()),
std::make_move_iterator(boxVec.end()),
std::back_inserter(tmpVec),
[&](std::unique_ptr<int> const& p){
return *p == 17; });
for (auto const& x: boxVec) {
(x? std::cout << *x: std::cout << "<null>") << " ";
}
std::cout << "\n";
}
Dereferencing a std::move_iterator<It>
will return a suitable rvalue of the iterator's value type. Since the rvalue is obtained using std::move(*it)
, it is a reference. That is, the value isn't stolen until the value is actually moved. The comparison uses a const&
, i.e., it won't steal the value. The assignment will become an rvalue assignment. The code also uses std::back_inserter()
to arrange for enough elements to be in the destination.
I don't think this is really a solid solution but I also don't think there is an algorithm like std::move_if()
(or a customization of any algorithm resulting in the same behavior). To really deal with conditionally moving objects I think you'd different access mechanism for the values passed into the predicate and the the way objects are assigned (property maps would address these issues but there is no proposal, yet, to add them to the C++ standard).
Upvotes: 7
Reputation: 42984
std::unique_ptr
is movable, not copyable.
So, you can't use std::copy_if()
with unique_ptr
instances.
If you really want to use std::copy_if()
, then you may use std::shared_ptr
instead of std::unique_ptr
, and then if you want to get rid of the old vector content, just destroy it using e.g. vector::clear()
.
Or, if shared_ptr
is too much overhead for you, or in any case you just want a vector of unique_ptr
s, then you may want to consider doing an in-place removing of unwanted vector elements using std::remove_if()
and the erase-remove idiom.
Upvotes: 0