我已经用重载运算符写出了我的类,但我正在尝试减少内存分配量(如Linux上的valgrind所示)。我理解在某些情况下,调用复制构造函数来为函数创建对象的本地副本,但我不确定哪些情况。就目前而言,我正在每个案例中创建一个新对象,所以我觉得如果我要使用已经复制的部分,我可以摆脱一些“新”调用。下面是我的operator +和operator + =供参考。
// ---------------------------------------------------------------------------
// operator+
// Adds two Poly objects
Poly Poly::operator+(const Poly& rhs) const {
//case where rhs has more terms
if (maxExponent < rhs.maxExponent) {
Poly temp(rhs);
for (int i = 0; i <= maxExponent; i++) {
temp.polynomial[i] += polynomial[i];
}
return temp;
}
else {
Poly temp(*this);
for (int i = 0; i <= rhs.maxExponent; i++) {
temp.polynomial[i] += rhs.polynomial[i];
}
return temp;
}
}
// ---------------------------------------------------------------------------
// operator+=
// Adds and assigns two Poly objects
Poly& Poly::operator+=(const Poly& rhs) {
*this = *this + rhs;
return *this;
}
这是我的算子=如果技巧依赖于此:
// ---------------------------------------------------------------------------
// operator=
// Assigns a Poly object to another
const Poly& Poly::operator=(const Poly& other) {
if (&other != this) {
delete[] polynomial;
maxExponent = other.maxExponent;
polynomial = new int[maxExponent + 1];
for (int i = 0; i <= maxExponent; i++) {
polynomial[i] = other.polynomial[i];
}
}
return *this;
}
答案 0 :(得分:2)
您正在寻找的技术称为“表达模板”。
您的operator+
需要两个Poly&
个对象,并返回should_be_added< Poly&, Poly& >
。如果再次添加,它会返回should_be_added< should_be_added<Poly&, Poly&>, Poly& >
(或者可能should_be_added< Poly&, Poly&, Poly& >
,如果您知道通勤情况并且您希望事情变得平坦,但这是额外的工作。)
should_be_added
然后转换为 - Poly
,或Poly
具有隐式should_be_added< T, U >&&
构造函数(效率move
这两个是等价的)。此时,您将在编译时获得要分配给Poly
的完整表达式树。通过大量的工作和关注,您可以有效地构建单个输出值。
一个好的开始方式是从您的operator+=(Poly const& o)
和operator+=(Poly&& o)
以及类似的“变异”运算符开始。这些原语可以使编写其他操作符更加容易。
您可能希望编写自定义Poly& operator=( should_be_added<T,U>&& src )
,以便它重用现有Poly
对象中的任何内存。一种简单的方法是在should_be_added
中使用Poly result( Poly&& src )
的方法,并将operator Poly()
实现为operator Poly() const { return result( Poly{} ); }
,operator=
为{{1} }}
现在,这一切都不容易 - 表达式{ swap( *this, src.result(std::move(*this)) ); return *this }
是中等深度template
- fu。但结果可能是你可以以自然的方式表达你的数学表达式,并且几乎没有任何东西。
请注意,template
类的高效move
语义应该很容易 - 只需Poly
内部缓冲区并清除源代码。
答案 1 :(得分:0)
在第一种情况下,使用operator+
,从概念上讲,你无能为力。你需要临时变量,你必须按值返回它。
在第二种情况下,您使用operator+=
实施operator+
,然后制作副本,然后使用operator=
将其复制到对象内。这是非常低效的。
出于上述原因,人们通常更愿意先实施operator+=
,然后将operator+
实施为:
Poly Poly::operator+(const Poly& rhs) {
return Poly(*this) += rhs;
}
这与你在这里所做的相反。
答案 2 :(得分:0)
我的解决方案是用以下想法重新实现Poly类:让我们无法修改字段'多项式'并使用shared_ptr在同一Poly的副本之间共享它。通过这种方式,我们可以使用O(1)复制运算符,而运算符+仍然是O(n) - 在乐观情况下可能有O(1):)
让我们也使用std :: vector而不是table,并注意我们的公共接口。作为回报,我们得到:
原谅我对运营商&lt;&lt;的草率实施。我将操作符+的乐观情况的实现留给了读者:)。
使用c ++ 11实现,因为我不是受虐狂。
#include <memory>
#include <vector>
#include <initializer_list>
#include <iostream>
class Poly {
public:
Poly() : polynomial_(NULL) {}
Poly(std::initializer_list<double> il)
{
polynomial_.reset(new std::vector<double>(il.begin(), il.end()));
}
unsigned max_exp() const
{
return polynomial_ ? polynomial_->size() : 0;
}
Poly operator+(const Poly& o) const
{
const bool has_bigger_exp = max_exp() > o.max_exp();
const Poly & poly_big = has_bigger_exp ? *this : o;
const Poly & poly_small = has_bigger_exp ? o : *this;
auto * tmp = new std::vector<double>(*poly_big.polynomial_);
for (unsigned i = 0; i < poly_small.max_exp(); ++i) {
tmp->at(i) += poly_small.polynomial_->at(i);
}
Poly ret_obj;
ret_obj.polynomial_.reset(tmp);
return ret_obj;
}
Poly& operator+=(const Poly& o)
{
*this = *this + o;
return *this;
}
private:
std::shared_ptr<const std::vector<double>> polynomial_;
friend std::ostream& operator<<(std::ostream& os, const Poly& obj);
};
std::ostream& operator<<(std::ostream& os, const Poly& obj)
{
if (obj.max_exp() == 0) {
os << "0" << std::endl;
return os;
}
for (unsigned i = obj.max_exp()-1; i > 0; --i) {
double param = obj.polynomial_->at(i);
if (param != 0) {
os << param << " * x^" << i << " + ";
}
}
os << obj.polynomial_->at(0) << std::endl;
return os;
}
int main() {
Poly a = {1, 2, 3};
Poly b = {4, 5};
Poly c = a + b;
Poly d;
std::cout << a << b << c << d;
a += {1, 1};
std::cout << a;
return 0;
}