user3665224
user3665224

Reputation: 1367

To copy a vector of unique pointer into new vector

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

Answers (3)

MatthiasB
MatthiasB

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 vector
  • vector.erase to delete the old, invalid unique_ptr

In 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));

Here is a live example

Upvotes: 3

Dietmar K&#252;hl
Dietmar K&#252;hl

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

Mr.C64
Mr.C64

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_ptrs, 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

Related Questions