سؤال

I have two classes and my conversion methods:

class A;
class B;

class A
{
    ...
};

class B
{
    ...

    static B fromA(A a)
    {
        B b;
        // ... some property conversions from A to B
        return b;
    }
    operator A()
    {
         // ... some property conversions from this(B) to A
        return A
    }
}

As one can see I defined a cast (for B -> A) + a static conversion (for A -> B) inside class B. It is forbidden to define any cast or conversion inside class A.

Suppose I have two vectors:

vector<vector<A> > vecA; // pre-defined
vector<vector<B> > vecB; // to be casted from vecA

What is the optimal(fastest) way to achieve data conversion between those, instead of my ugly solution:

using namespace std;

vecB.resize(vecA.size());
for(int i = 0; i<vecA.size(); i++)
{
    vecB[i].resize(vecA[i].size());
    for(int j = 0; j<vecA[i].size(); j++)
    {
        vecB[i][j] = B::fromA(vecA[i][j]);
    }
}
هل كانت مفيدة؟

المحلول

define operator= for B

B::operator=(const A& a)
{
// actual code to copy from a to b.
}

in your code change the line

vecB[i][j] = B::fromA(vecA[i][j]);

to

vecB[i][j] = vecA[i][j];

it will eliminate many temporary A & B objects that are created in your original code.

Also instead of using vecB[i][j] use iterators. Following code may have some syntax errors

vecB.resize(vecA.size());

vector<vector<A> >::const_iterator itA1;
vector<vector<B> >::const_iterator itB1;
vector<A> >::const_iterator itA2;
vector<B> >::const_iterator itB2;


for(itA1=vecA.begin(), itB1= vecB.begin(); 
         itA1 != vecA.end(); 
        ++itA1, ++itB1)
{
    for(itA2 = (*itA1).begin(), itB2=(*itB1).begin(); 
      itA2 != (*itA1).end(); 
      ++itA2, ++itB2)
    {
        (*itB2) = *itA2;
    }
}

نصائح أخرى

You can use algorithms and iterators instead of hand-crafted for loops if you want (that might be a bit faster if your standard library implementation is heavily optimised), but the core complexity remains the same - you have to convert each element individually, no way around that.

You can use std::transform to make your code a bit shorter and easier to read. However I think you will get best performance if you define the method B fromA(A a) a void method that takes an output parameter of type B&. I.e. make your method declaration static void fromA(const A&, B&). This way for pre-c++11 code you will avoid a copy of the returned object.

Alternatively make the method fromA instance method instead of a static method and again make it void - the method would modify the current instance. Another option is as pointed in other answers - to create a constructor of B that takes a const A& as its only parameter.

You could define an implicit conversion constructor to convert A to B, rather than a named function:

B(A const & a) {
    // ... some property conversions from A to B
}

Now you could convert a single vector with something like

std::vector<B> vecB(vecA.begin(), vecA.end());  // declare a new vector
vecB.assign(vecA.begin(), vecA.end());          // reassign an existing vector

You'll still need a loop to reassign a vector of vectors; perhaps something like:

vecB.clear();
vecB.reserve(vecA.size());
for (auto const & vA : vecA) {
    vecB.push_back(std::vector<B>(vA.begin(), vA.end()));
}

This is no faster than your version, but involves writing less code.

instead of defining:

static B fromA(A a);

define:

B(A a) as a conversion constructor

generally this is avoided by using the explicit keyword but here this seems to be exactly what you want since you need to construct a B from A

this would simplify:

vecB[i][j] = B::fromA(vecA[i][j]);

to:

vecB[i][j] = vecA[i][j];

which looks like a good candidate for `std::copy

If you want to write nice code you can use either std::transform or std::assign, or std::for_each but if you want fast code then it will be hard to write something faster than this:

vecB.resize(vecA.size());
for (unsigned int i = 0, asize = vecA.size(); i < asize; i++)
{
    const vector<A> & vin = vecA[i];
    vector<A> & vout = vecB[i];

    vout.resize(vin.size());
    for (unsigned int j = 0, bsize = vout.size(); j < bsize; j++)
    {
        vout[j].createFromA(vin[j]);
    }
}

Notice the asize and bsize initialization is done like such to prevent aliasing problems. Also createFromA should be a member function that directly initializes the class members without other class copy/assignment.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top