1

My first problem is that I cannot instantiate a vector of pointers and the second problem is that the push_back does not work with make_pair. Can someone please help?

The error is

no matching function for call to ‘std::unique_ptr<Base>::unique_ptr(Derived&)’

and

error: no matching function for call to ‘std::vector<std::pair<std::unique_ptr<Base>, std::unique_ptr<Base> > >::push_back(std::pair<Base*, Base*>)’

#include <vector>
#include <memory>

void someFunction(std::vector<std::unique_ptr<Base> > & vec) {

    std::vector<std::unique_ptr<Base>>::iterator it = vec.begin();

    std::vector<std::pair<std::unique_ptr<Base>, std::unique_ptr<Base> > > pairWise;
    pairWise.push_back(std::make_pair((*it).get(), (*it).get()));

}

int main(int argc, char *argv[]) {


    Base a;
    std::vector<Derived> derivedObjects(2);
    std::vector<std::unique_ptr<Base> > vecPtr = {derivedObjects.begin(), derivedObjects.end()};
    someFunction(vecPtr);


}
infoclogged
  • 3,641
  • 5
  • 32
  • 53

1 Answers1

2

Your code here:

std::vector<Derived> derivedObjects(2);
std::vector<std::unique_ptr<Base> > vecPtr = {derivedObjects.begin(), derivedObjects.end()};

Isn't quite correct. I suspect you wanted to use std::vector's range based constructor to make a copy of all the Derived objects in derivedObjects into a new vector of std::unique_ptr<Base> - it wouldn't work, because there is no valid constructor for std::unique_ptr<Base> that takes Derived.

Secondly, your use of uniform brace initializer there isn't quite correct.


I suspect you want this:

std::vector<Derived> derivedObjects(2);
std::vector<std::unique_ptr<Base>> vecPtr;
std::transform(derivedObjects.begin(), derivedObjects.end(), std::back_inserter(vecPtr),
    [](auto& p){ return std::make_unique<Base>(p); });

What this does is to

  • take each Derived object in derivedObjects and calls our lambda object, which in-turn transforms that Derived object to a std::unique_ptr<Base> and returns it.
  • The returned "transformation" is then assigned to the iterator returned by std::back_inserter (and of cause incremented). std::back_inserter is more a less an "STL iterator style" of doing std::vector<T, Alloc>::push_back(...)

UPDATE

In regards to your comment:

void someFunction(std::vector<std::unique_ptr<Base> > & vec) {
    std::vector<std::unique_ptr<Base>>::iterator it = vec.begin();
    std::vector<std::pair<std::unique_ptr<Base>, std::unique_ptr<Base> > > pairWise;
    pairWise.push_back(std::make_pair((*it).get(), (*it).get()));
}

It's unclear whether you want to push a copy of std::pair or std::unique_ptr<Base>s into pairwise, because std::unique_ptrs cannot be copied. ONly moved.

If you want to move: You can replace the last line with:

pairWise.emplace_back(std::move(*it), std::move(*it));
//You shouldn't rely on the UB above of moving twice from the same object

If it's a copy (a bit nasty because your design is quite not nice or unclear to me):

pairWise.emplace_back(std::make_unique<Base>(*(*it).get()), std::make_unique<Base>(*(*it).get()));
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • It works. I just had to change the compiler settings to c++14, since it did not work in c++11. Can you please address the second problem with make_pair? – infoclogged Feb 08 '18 at 19:09
  • I did want to make a pair of identical pointers ( pointing to the derived class ) and put them into the variable pairWise. But I have to read your answer thorougly first. Also, if the base class is abstract, then the code with std::transform doesnt work. – infoclogged Feb 08 '18 at 20:01
  • @infoclogged, you cannot have a `std::unique_ptr` of an abstract base class. In fact, if `Base` was abstract, then your code snippet would never have worked, even from the declaration, `Base a` - Cannot work – WhiZTiM Feb 08 '18 at 20:29
  • Yes, I got it.. The working copy is much more complicated than the example I posted here. But I have got the whole point. The use of unique_ptr is absolutely not required here. Thanks for your time. – infoclogged Feb 08 '18 at 20:42