重载运算符以合并矢量

Overloading operator to merge vectors

本文关键字:合并 运算符 重载      更新时间:2023-10-16

我想在一个以向量为成员变量的类中重载运算符+,以便实现两个不同对象的向量的合并。换句话说,我希望创建一个新的对象,它将一行中两个初始向量的向量元素都作为向量。我尝试了以下代码,在operator+中收到一个关于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;
}

此外,第二个copy语句通常对合并两个向量有效吗?

更新:我在执行时遇到一个错误,说迭代器不适用于此语句。怎么了
tempVector.insert(tempVector.end((,param.getVector((.begin((,aram.getVector.eend(((;

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

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+作为一个自由函数,并通过const引用获取参数。目前,operator+是非常量的,因此只能在非常量向量上调用,并通过复制获取其第二个参数。如果声明getVectorconst 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);
}

如果要为您的类型实现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;
}

其优点是,您只需要再多几行代码,就可以免费获得一个新操作,它不需要友谊或为类型的内部细节提供访问器,并且对于用户代码不需要维护左手边运算符的情况,它是高效的(不需要复制(。同时CCD_ 21的实现可以作为一个自由函数(关于类型的对称性,即转换1(和有效的(在C++11编译器中,如果TestVector有一个移动构造函数,那么它只会复制每个元素一次,因为唯一的成员是一个可移动的向量;在C++03中,return语句中有一个额外的副本,可以通过deafult构造和交换来删除(。

1注意:您可能需要考虑使TestVector( std::vector<int> const & )显式,以避免隐式转换为TestVector