Контейнерное литье

У меня есть два класса и мои методы преобразования:

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
    }
}

Как видно, я определил приведение (для B -> A) + статическое преобразование (для A -> B) внутри класса B. Запрещено определять любое приведение или преобразование внутри класса A.

Предположим, у меня есть два вектора:

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

Какой оптимальный (самый быстрый) способ добиться преобразования данных между ними, вместо моего уродливого решения:

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]);
    }
}

6 ответов

Решение

Определить оператор = для B

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

в вашем коде поменяйте строку

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

в

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

это исключит многие временные объекты A & B, созданные в вашем исходном коде.

Также вместо использования vecB[i][j] используйте итераторы. Следующий код может иметь некоторые синтаксические ошибки

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;
    }
}

Вместо определения:

static B fromA(A a);

определить:

B(A a) как конструктор преобразования

как правило, этого можно избежать с помощью explicit ключевое слово, но здесь это, кажется, именно то, что вы хотите, так как вам нужно построить B из A

это упростило бы:

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

чтобы:

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

который выглядит как хороший кандидат для `std::copy

Вы можете определить конструктор неявного преобразования для преобразования A в Bвместо именованной функции:

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

Теперь вы можете конвертировать один вектор с чем-то вроде

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

Вам все еще понадобится цикл для переназначения вектора векторов; возможно что-то вроде:

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

Это не быстрее, чем ваша версия, но включает в себя написание меньшего количества кода.

Вы можете использовать std::transform, чтобы сделать ваш код немного короче и проще для чтения. Однако я думаю, что вы получите лучшую производительность, если вы определите метод B fromA(A a) пустой метод, который принимает выходной параметр типа B&, Т.е. сделать декларацию вашего метода static void fromA(const A&, B&), Таким образом, для кода до с ++11 вы избежите копирования возвращаемого объекта.

В качестве альтернативы сделать метод fromA метод экземпляра вместо статического метода и снова делает его недействительным - метод изменяет текущий экземпляр. Другой вариант, как указано в других ответах, - создать конструктор B, который принимает const A& как его единственный параметр.

Вы можете использовать алгоритмы и итераторы вместо созданных вручную for циклы, если вы хотите (это может быть немного быстрее, если ваша стандартная реализация библиотеки сильно оптимизирована), но основная сложность остается той же - вы должны конвертировать каждый элемент по отдельности, никак иначе.

Если вы хотите написать хороший код, вы можете использовать либо std::transform или же std::assign, или же std::for_each но если вам нужен быстрый код, тогда будет сложно написать что-то быстрее, чем это:

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]);
    }
}

Обратите внимание на asize а также bsize инициализация выполняется так, чтобы избежать проблем с наложением. Также createFromA должна быть функцией-членом, которая непосредственно инициализирует членов класса без копирования / назначения другого класса.

Другие вопросы по тегам