我想在一个具有向量作为成员变量的类中重载operator +,以便执行两个不同对象的向量的合并。换句话说,我想要创建一个新对象,它具有一行中两个初始向量的向量元素作为向量。我尝试以下代码,我在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;
}
此外,第二个复制语句是否有效合并两个向量?
更新:我在执行时遇到错误,说明迭代器在此语句中不兼容。怎么了?
tempVector.insert(tempVector.end(),param.getVector()。begin(),param.getVector()。end());
答案 0 :(得分:1)
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());
}
};
答案 1 :(得分:1)
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+
是非常量的,因此只能在非常量向量上调用,并通过复制获取其第二个参数。如果宣布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);
}
答案 2 :(得分:1)
如果您要为您的类型实施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语句中有一个额外的副本可以被deafult删除构建和交换)。
1 注意:您可能需要考虑明确TestVector( std::vector<int> const & )
,以避免隐式转换为TestVector
。