Перегрузка оператора для объединения векторов - PullRequest
0 голосов
/ 04 декабря 2011

Я хочу перегрузить оператор + в классе, который имеет вектор в качестве переменной-члена, чтобы выполнить слияние векторов двух разных объектов. Другими словами, я бы хотел, чтобы был создан новый объект, который имеет в качестве вектора оба элемента векторов двух начальных векторов в строке. Я пытаюсь следующий код, и я получаю ошибку в операторе + относительно std :: copy. В чем проблема?

class TestVector
{
    std::vector<int> myVector;

public:
    TestVector(){};
    TestVector(std::vector<int>);
    std::vector<int> getVector();
    TestVector operator +(TestVector);

};

std::vector<int> TestVector::getVector()
{
   return myVector;
}

TestVector TestVector::operator+(TestVector param)
{

    std::vector<int> tempVector;
    std::vector<int> paramVector = param.getVector();

    std::copy(paramVector.begin(), paramVector.end(), tempVector);
    std::copy(myVector.begin(), myVector.end(), tempVector.end());

    TestVector TestVector1(tempVector);

    return TestVector1;

}

Кроме того, допустимо ли второе утверждение копирования для объединения двух векторов в целом?

Обновление: Я получил ошибку во время выполнения, в которой говорится, что итераторы несовместимы с этим оператором. Что не так?
tempVector.insert (tempVector.end (), param.getVector (). begin (), param.getVector (). end ());

Ответы [ 3 ]

1 голос
/ 04 декабря 2011

Третий параметр std::copy должен быть своего рода итератором вывода.Самым безопасным будет использовать итератор вставки.После #include <iterator> вы должны иметь возможность сделать что-то вроде:

std::copy(paramVector.begin(), paramVector.end(), std::back_inserter(tempVector));
std::copy(myVector.begin(), myVector.end(), std::back_inserter(tempVector));

std::back_inserter - это шаблон вспомогательной функции, который создает соответствующий back_insert_iterator для данного контейнера.

Такжеобратите внимание, что вы делаете довольно много копий.Лично я бы сделал operator+ свободной функцией и взял бы параметры по константной ссылке.В данный момент ваш operator+ неконстантен, поэтому может вызываться только для неконстантных векторов и принимает свой второй параметр при копировании.Если бы getVector было объявлено: const TestVector& getVector() const;, тогда вы могли бы сделать что-то вроде этого.

TestVector operator+(const TestVector& lhs, const TestVector& rhs)
{
    std::vector<int> ret( lhs.getVector() );
    ret.insert( ret.end(), rhs.getVector().begin(), rhs.getVector().end() );
    return TempVector(ret);
}
1 голос
/ 04 декабря 2011

Если вы собираетесь реализовать operator+ для своего типа, я бы рекомендовал вам также реализовать operator+= в качестве функции-члена, а затем operator+ в терминах предыдущего оператора:

// As a public member function
TestVector& TestVector::operator+=( const TestVector& rhs ) {
   myVector.insert( myVector.end(), rhs.myVector.begin(), rhs.myVector.end();
   return *this;
}

TestVector operator+( TestVector lhs, const TestVector& rhs ) {
   lhs += rhs;
   return lhs;
}

Преимущество состоит в том, что вам нужно всего лишь еще пару строк кода, и вы получаете новую операцию бесплатно, она не требует дружбы или предоставления доступа к внутренним деталям типа и эффективна (не требует копирования) для случай, когда пользовательский код не нуждается в поддержке левого оператора. В то же время реализация operator+ может быть сделана как свободная функция (симметрия относительно типов --ie преобразования 1 ) и эффективная (в компиляторе C ++ 11 она будет копировать каждый элемент только один раз, если TestVector имеет конструктор перемещения, который он должен иметь, поскольку единственный член - это вектор, который является подвижным; в C ++ 03 есть дополнительная копия в операторе return, которая может быть удалена путем создания и замены по умолчанию).

1 Примечание. Возможно, вы захотите сделать явное TestVector( std::vector<int> const & ), чтобы избежать неявного преобразования в TestVector.

1 голос
/ 04 декабря 2011

Третий аргумент std::copy должен быть итератором, а не контейнером. Вы можете использовать std::back_inserter таким образом:

std::copy(paramVector.begin(), paramVector.end(), std::back_inserter(tempVector));

Вторая копия будет скомпилирована, поскольку std::end() возвращает итератор, но он сломается, потому что итератор просто указывает на конец вектора. Вектор не будет расти, когда std::copy попытается присвоить ему; это просто вызовет неопределенное поведение. Опять же, std::back_inserter решает проблему.

В любом случае вам вообще не нужен std::copy, поскольку std::vector обеспечивает необходимую семантику напрямую:

TestVector TestVector::operator+(const TestVector& v)
{
    std::vector<int> t(myVector);
    t.insert(t.end(), v.myVector.begin(), v.myVector.end());
    return TestVector(t);
}

И не забывайте использовать const &…, чтобы избежать такого большого копирования. Например, второй конструктор копирует входной вектор без необходимости, а getVector() копирует внутренний вектор без необходимости.

Даже приведенное выше решение копирует временный вектор хотя бы один раз, чего можно избежать с помощью специального конструктора:

class TestVector
{
    std::vector<int> myVector;

public:
    TestVector() { }
    TestVector(const std::vector<int>& v) : myVector(v) { }
    const std::vector<int>& getVector() const { return myVector; }
    TestVector operator+(const TestVector& v) const {
        return TestVector(op_add(), *this, v);
    }

private:
    struct op_add { };
    TestVector(op_add, const TestVector& a, const TestVector& b) : myVector(a) {
        myVector.insert(myVector.end(), b.myVector.begin(), b.myVector.end());
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...