Append vector of unique ptr to another via member function - c++

I want to move a vector of unique ptrs to a vector of unique ptrs I have stored in a class. I have reduced this to a minimum example here:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class A
{
public:
A() = default;
};
class B
{
public:
void AddAs(const vector<unique_ptr<A>>& vv)
{
vec.insert(vec.end(),
std::make_move_iterator(vv.begin()),
std::make_move_iterator(vv.end())
);
}
vector<unique_ptr<A>> vec;
};
int main() {
vector<unique_ptr<A>> v;
for(int i=0; i<10; ++i)
{
v.push_back(make_unique<A>());
}
B b;
b.AddAs(v);
return 0;
}
https://ideone.com/76iNIM
This trying to follow the answer from Inserting a vector of unique_ptr into another vector
But this doesn't compile as it says that is using the copy operator.
I am sure this is a stupid question, but I am new to C++ and I am struggling to see where the copy is.
Thank you

You cannot move from a vector, that you passed by const reference, as moving requires modification. So change that method to:
void AddAs(vector<unique_ptr<A>>&& vv)
Passing by value will also work:
void AddAs(vector<unique_ptr<A>> vv)
Note you need to change calling code:
b.AddAs(std::move(v));
which is actually good as shows the reader that vector would be moved from.
live example

Related

transform vector of shared_ptr with non const elements to vector of shared_ptr with const elements

I have a class A containing a vector of shared_ptr<B>.
I implemented a getter to this vector.
In some cases, it would be nice to ensure that the content in B does not change (make B read only or a const reference).
If I would not have used vector<shared_ptr<B>> but rather vector<B> I could simply write two getters, one returning a const reference (read only), and one returning a reference only (manipulation possible). #
Is there a way to do the same thing with a vector<shared_ptr<B>>?
Maybe it is easier to understand the problem in this code:
#include <vector>
#include <memory>
using namespace std;
class B{
public:
explicit B(int i) : i_{i} {}
void set_i(int i){i_ = i;}
private:
int i_ = 0;
};
class A{
public:
const vector<shared_ptr<B>> &get_vb(){return vb;}
// const vector<shared_ptr<const B>> &get_vb_const(){return vb;} // I would like to return a const vector with const elements in some cases
private:
vector<shared_ptr<B>> vb{make_shared<B>(1), make_shared<B>(10), make_shared<B>(100)};
};
int main() {
A a;
const auto &vb = a.get_vb();
vb[0]->set_i(2);
// const auto &vb_const = a.get_vb_const(); // somehow I would like to gain this vector without being able to modify the elements
// vb_const[0]->set_i(2); // should throw error
return 0;
}
You need to construct a new vector with the desired elements:
const vector<shared_ptr<const B>> get_vb_const() const {
return vector<shared_ptr<const B> > {vb.cbegin(), vb.cend()};
}
Note that the function doesn't return a reference now because we are creating a temporary and returning it.
transform vector of shared_ptr with non const elements to vector of shared_ptr with const elements
You can use the constructor of vector that accepts a pair of iterators to perform the conversion.
You can avoid the overhead of allocating and copying a vector by implementing a custom const iterator for your class.

automatic conversion between stl vectors

What I want is to copy an std::vector<int> to another std::vector<myStruct> with assignment operator in which myStruct can be assigned an int. So I wrote this piece of code:
#include <vector>
#include <iostream>
using namespace std;
struct myStruct
{
myStruct(int& a) : _val(a) { }
myStruct(int&& a) : _val(a) { }
myStruct& operator=(int& a)
{
_val = a;
return *this;
}
int _val;
};
int main()
{
vector<int> ivec;
ivec.push_back(1);
vector<myStruct> svec = ivec;
return 0;
}
And it gives me error as it cannot find a valid conversion between std::vector<myStruct> and std::vector<int> although int can implicitly be converted to myStruct. On the other hand, assign operator cannot be declared outside the class so I deduce writing an operator manually is not an option. So what should I do in this situation?
*** UPDATE:
As Blastfurnace and others said this can be solved using this code instead of assignment:
vector<myStruct> svec(ivec.begin(), ivec.end());
But imagine the situation in which I want to write a library and want to handle this in the library itself so the user can just write std::vector<myStruct> svec = someFunction() in which someFunction returns std::vector<int>. Isn't there any solution for this?
You could use the constructor overload that takes an iterator range:
vector<myStruct> svec(ivec.begin(), ivec.end());
You can use vector<myStruct> svec(ivec.begin(), ivec.end()); instead.
You could also use std::copy(ivec.begin(), ivec.end(), std::back_inserter(svec)); or svec.assign(ivec.begin(), ivec.end()); as it might be better in case you assign multiple times as it can reuse the capacity of the vector<myStruct> after it was cleared.
Your best bet is having a conversion function
std::vector< myStruct> convertVector( const std::vector< int> & other)
{
return std::vector< myStruct> ( ivec.begin(), ivec.end() );
}
that would automatically use return value optimization so no overhead for copying the data twice (you just copy data once instead when you iterate the "other" vector).
Just for the sake of completeness:
By using custom datatypes it is possible adding custom type conversion but I guess that's generally a bad Idea and you may not be interested in, anyway:
class IntVector: public std::vector<int>{
public:
//conversion operator (note a VERY BAD IDEA using this, may come in handy in few cases)
operator myStructVector () {
return convertVector(*this);
}
}
class myStructVector: public std::vector< myStruct>{
//....
};
usage:
int main()
{
IntVector ivec;
ivec.push_back(1);
myStructVector svec = (myStructVector)ivec;
return 0;
}
I would discourage going this way anyway ^^

C++ Generic code for deleting pointer value in Map and vector of pointers

I have some generic code for deleting pointers within a vector or a value of a Map.
Is there a better way of doing this (without using shared_ptrs or any o fthe tr1 extensions )?
Also is the code correct?
Here is my code:
I have a namespace
#ifndef CONTAINERDELETE_H
#define CONTAINERDELETE_H
#include <functional>
#include <map>
#include <vector>
#include <algorithm>
namspace ContainerDelete{
template<class A, class B>
struct DeleteMap
{
bool operator()( pair<A,B> &x) const
{
delete x.second;
return true;
}
};
template<class T>
struct DeleteVector
{
bool operator()(T &x) const
{
delete x;
return true;
}
};
}
#endif
I would then use this namespace in some bit of code to delete a map or vector.
Test Map deletion.
#include "ContainerDelete.h"
using namespace std;
// Test function.
void TestMapDeletion()
{
// Add 10 string to map.
map<int,B*> testMap;
for( int Idx = 0; Idx < 10; ++Idx )
{
testMap[Idx] = new B();
}
// Now delete the map in a single line.
for_each( testMap.begin(),
testMap.end(),
ContainerDelete::DeleteMap<int,B*>());
}
Test Vector Deletion
// Test Function.
void TestVectorDeletion()
{
// Add 10 string to vector.
vector<B*> testVector;
for( int Index = 0; Index < 10; ++Index )
{
testVector.push_back( new B());
}
// Now delete the vector in a single line.
for_each( testVector.begin(),
testVector.end(),
ContainerDelete::DeleteVector<B*>());
}
Thanks,
Mike
Better would be if reduce the genericity as:
struct DeleteVector
{
template<class T> //use the template here!
void operator()(T &x) const
{
delete x;
}
};
if you do so, then you could simply write this:
for_each(testVector.begin(),
testVector.end(),
ContainerDelete::DeleteVector());
No need to pass type argument when you use DeleteVector, for it is not a class template anymore!
Similarly, you can implement DeleteMap functor.
You should also rename DeleteVector to DeleteT, and DeleteMap to DeletePairSecond, as both of these can be used more generically. For example, DeleteT can be used even with std::list, or even with arrays.
The code is ok. I can't imagine any other ways to delete the pointers. All you can do is to reduce explicit type specification like in upper question. I know one more uglier way to do it: functions deduce types of their template parameters. So you can write template function with the first argument - vector, second - ptr and then use std::bind of vector parameter to make this function accepting one parameter - ptr.
But functor is better and more flexible.

Copying a vector of pointers

I have a std::vector<A*> which I need to deep copy to another vector using A::Clone().
Instead of using handwritten loops, I was wondering whether I could use for_each or any Standard Library algorithm for this.
The appropriate algorithm is std::transform and you can turn member function invocation into a unary functor with std::mem_fun
Example:
#include <vector>
#include <functional>
#include <algorithm>
#include <iterator>
class X
{
public:
X* clone();
};
int main()
{
std::vector<X*> vec1, vec2;
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), std::mem_fun(&X::clone));
}
If the target vector is already the same size as the input range, you can pass vec2.begin() as the third argument. Use back_inserter if the target is empty (or you want to append to it).
Perhaps something like this would work:
class DeepCopy {
public:
A* operator() (A* aP) {
return aP->Clone();
}
}
int main()
{
vector<A*> vA;
vector<A*> vA2;
transform(vA.begin(), vA.end(), back_inserter(vA2), DeepCopy());
return 0;
}
You could use boost::ptr_vector<A> instead of std::vector<A*>.
This has a template parameter CloneAllocator, for which you could pass the relevant custom cloner.

Can a functor retain values when passed to std::for_each?

According to the first answer to this question, the functor below should be able to retain a value after being passed to foreach ( I couldn't get the struct Accumulator in the example to compile, so built a class).
class Accumulator
{
public:
Accumulator(): counter(0){}
int counter;
void operator()(const Card & c) { counter += i; }
};
Example usage ( as per the example )
// Using a functor
Accumulator acc;
std::for_each(_cards.begin(), _cards.end(), acc);
// according to the example - acc.counter contains the sum of all
// elements of the deque
std::cout << acc.counter << std::endl;
_cards is implemented as a std::deque<Card>. No matter how long _cards gets, acc.counter is zero after the for_each completes. As I step through in the debugger I can see counter incrementing, however, so is it something to do with acc being passed by value?
This was just asked here.
The reason is that (as you guessed) std::for_each copies its functor, and calls on it. However, it also returns it, so as outlined in the answer linked to above, use the return value for for_each.
That said, you just need to use std::accumulate:
int counter = std::accumulate(_cards.begin(), _cards.end(), 0);
A functor and for_each isn't correct here.
For your usage (counting some, ignoring others), you'll probably need to supply your own functor and use count_if:
// unary_function lives in <functional>
struct is_face_up : std::unary_function<const Card&, const bool>
{
const bool operator()(const card& pC) const
{
return pC.isFaceUp(); // obviously I'm guessing
}
};
int faceUp = std::count_if(_cards.begin(), _cards.end(), is_face_up());
int faceDown = 52 - faceUp;
And with C++0x lambda's for fun (just because):
int faceUp = std::count_if(_cards.begin(), _cards.end(),
[](const Card& pC){ return pC.isFaceUp(); });
Much nicer.
Yes, it's definitely linked to acc being passed by value.
Modify your accumulator as follows :
class Accumulator
{
public:
Accumulator(): counter(new int(0)){}
boost::shared_ptr<int> counter;
void operator()(int i) { *counter += i; }
int value() { return *counter; }
};
This is because internally the std::for_each() makes a copy of the functor (as it is poassable to pass temporary object). So internally it does do the sum on the copy not on the object you provided.
The good news is that std::for_each() returns a copy of the functor as a result so you can access it from there.
Note: There are other standard algorithms you could use. Like std::accumulate().
But suppose this is just a simplified example and you need for_each() to something slightly tricker than the example there are a couple of techniques to allow you access to the accumulator object.
#include <iostream>
#include <algorithm>
#include <vector>
class Card{ public: int i;};
class Accumulator
{
public:
Accumulator(): counter(0){}
int counter;
void operator()(const Card & c) { counter += c.i; }
};
int main()
{
std::vector<Card> cards;
Accumulator a = std::for_each(cards.begin(), cards.end(), Accumulator());
std::cout << a.counter << std::endl;
}
Alternatively you can change you Accumalator to increment a reference that is used within the current scope.
#include <iostream>
#include <algorithm>
#include <vector>
class Card{ public: int i;};
class Accumulator
{
int& counter;
public:
// Pass a reference to constructor.
// Copy construction will pass this correctly into the internal object used by for_each
Accumulator(int& counterRef): counter(counterRef){}
void operator()(const Card & c) { counter += c.i; }
};
int main()
{
std::vector<Card> cards;
int counter = 0; // Count stored here.
std::for_each(cards.begin(), cards.end(), Accumulator(counter));
std::cout << counter << std::endl;
}