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.
Related
I want to create and fill a set from the contents of a member variable of each entry of a vector. This is what I am doing:
struct S { int i; };
int main()
{
std::vector<S*> structPtrs;
// code to fill the above vector
// create set from the above vector
std::set<int> setInts;
for (auto it = structPtrs.begin(); it != structPtrs.end(); ++it)
{
setInts.insert((*it)->i);
}
}
Is there an STL way to do it? Or via any available method(s) in <algorithm>?
You can always apply std::transform from the range defined by the vector onto the "range" defined by an std::inserter:
transform(begin(structPtrs), end(structPtrs),
inserter(setInts, end(setInts)), [] (S* s) {
return s->i;
});
That should be more than enough use of the standard library.
If you are willing to look beyond the standard library, there is also the option of using something like boost::transform_iterator, which will allow you to move the range transformation into the set's initialization:
auto transfomer = [](S* s) { return s->i; };
std::set<int> setInts(
boost::make_transform_iterator(begin(structPtrs), transfomer),
boost::make_transform_iterator(end(structPtrs), transfomer)
);
You could use std::transform with an appropriate lambda and an insert iterator:
std::transform(structPtrs.begin(), structPtrs.end(), std::inserter(setInts, setInts.end()),
[](S* sp) { return sp->i; });
But personally, I find a simple range for loop to be much easier to follow:
for (S* sp : structPtrs)
setInts.insert(sp->i);
There is one other way you can do this. If you add conversion operator to int to your struct you can just use range constructor directly
#include <iostream>
#include <set>
#include <vector>
using namespace std;
struct test {int i; operator int() {return i;}};
int main() {
vector<test> v;
v.push_back(test{433});
v.push_back(test{533});
set<int> s(v.begin(), v.end());
cout << *(++s.begin());
return 0;
}
https://www.ideone.com/qJwtwc
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
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 ^^
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.
I've found myself writing
for(int i=0;i<myvec.size();i++)
myvec[i]->DoWhatever(param);
a lot, and I'd like to compress this into a foreach statement, but I'm not sure how to get param in there without going super-verbose. I've also got things like
for(int i=0;i<myvec.size();i++)
if(myvec[i]->IsOK())
myvec[i]->DoWhatever(param);
and I'd like to rewrite that guy too. Any thoughts?
Oh, also, for various reasons, I don't want to use boost.
#include <vector>
#include <algorithm>
#include <functional>
class X
{
public:
void doWhat(int x) {}
bool IsOK() const {return true;}
};
class CallWhatIfOk
{
public:
CallWhatIfOk(int p): param(p) {}
void operator()(X& x) const
{ if (x.IsOK()) {x.doWhat(param);}}
private:
int param;
};
int main()
{
std::vector<X> myVec;
std::for_each( myVec.begin(),
myVec.end(),
std::bind2nd(std::mem_fun_ref(&X::doWhat),4)
);
std::for_each( myVec.begin(),
myVec.end(),
CallWhatIfOk(4)
);
}
Oh, also, for various reasons, I don't want to use boost.
Valid decision, but most likely the wrong one. Consider Boost as an extension to the STL. C++ is a library-driven language. If you don't take this into account, your code will be qualitatively inferior.
While std::for_each can be used here, the absence of lambda expressions in C++ until C++0x makes this tedious. I advocate using Boost.ForEach! It makes this much easier:
foreach (yourtype x, yourvec)
if (x.IsOK())
x.Whatever();
My preferred solution is usually to write a functor to do what I need:
struct doWhatever {
doWhatever(const Param& p) p(p) {}
void operator(MyVec v&, Param p) {
v.DoWhatever(param);
}
private:
Param p;
};
And then the loop:
std::for_each(myvec.begin(), myvec.end(), doWhatever(param));
Depending on how many variations of this you have, this might be a bit too verbose.
There are plenty of options for doing it inline though.
boost::lambda would let you construct the function you need at the call-site. boost::bind (or the standard library bind functions) would let you bind the parameter param to the function so you don't need to supply it as an argument every time.
boost::lambda is probably the most concise and flexible approach. I usually use the plain functor approach because the syntax is easier to remember. ;)
well when we have compilers that support C++0x lambda expresions, this becomes straightforward and minimally invasive:
std::for_each(myvec.begin(),myvec.end(),[&](X& item){
item->DoWhatever(param);
});
and the second example may look like this:
std::for_each(myvec.begin(),myvec.end(),[&](X& item){
if(item->IsOK())
myvec[i]->DoWhatever(param);
});
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/lambda/if.hpp>
#include <boost/lambda/bind.hpp>
struct A
{
bool IsOK () { return true; }
void DoWhatever (int param) {}
};
struct B
{
bool IsOk (A * a) { return true; }
void DoWhatever (A * a, int param) {}
};
typedef std::vector<A *> Myvec;
void main()
{
Myvec myvec;
int param = 1;
B b;
// first challenge using boost::bind (fnct in the same class)
std::for_each (myvec.begin(), myvec.end(),
boost::bind (&A::DoWhatever, _1, param));
// first challenge using boost::bind (fnct in an external class)
std::for_each (myvec.begin(), myvec.end(),
boost::bind (&B::DoWhatever, &b, _1, param));
// second challange using boost::lambda (fnct in the same class)
std::for_each (myvec.begin(), myvec.end(),
boost::lambda::if_then(
boost::lambda::bind (&A::IsOK, boost::lambda::_1),
boost::lambda::bind (&A::DoWhatever, boost::lambda::_1, param)
)
);
// second challange using boost::lambda (fnct in an external class)
std::for_each (myvec.begin(), myvec.end(),
boost::lambda::if_then(
boost::lambda::bind (&B::IsOK, &b, boost::lambda::_1),
boost::lambda::bind (&B::DoWhatever, &b, boost::lambda::_1, param)
)
);
}
You can simplify it by using namespaces...
If you are using GCC you can define something like:
#define foreach(element, array) \
for(typeof((array).begin()) element = (array).begin(), __end_##element = (array).end();\
element != __end_##element;\
++element)
and use it after like this:
foreach(element, array){
element->DoSomething(); //or (*element)->DoSomething() if type is already a pointer
}
I use this on a custom array but it works fine with std::vector too.