C++ operator +和*non-const重载

Jon*_*ius 2 c++ operator-overloading const-correctness

我有以下棘手的问题:我已经实现了一个(相当复杂的)类,它以多小波为基础表示数学函数.由于+, - 和*等操作在此上下文中非常自然,因此我为此类实现了重载运算符:

FunctionTree<D> operator+(FunctionTree<D> &inpTree);
FunctionTree<D> operator-(FunctionTree<D> &inpTree);
FunctionTree<D> operator*(FunctionTree<D> &inpTree);
Run Code Online (Sandbox Code Playgroud)

操作员在简单的非链式操作中工作得更好,甚至在链接操作员的某些情况下也是如此.声明如

FunctionTree<3> y = a * b + c;
FunctionTree<3> z = a * b + b;
Run Code Online (Sandbox Code Playgroud)

编译看似工作正常.第一行实际上是正常的,但第二行导致valgrind告诉你关于内存被释放的已释放区域和正在访问的未初始化变量的严峻故事.此外,声明如

FunctionTree<D> y = a + b * c;
Run Code Online (Sandbox Code Playgroud)

甚至不会编译,因为我没有定义(一个模糊的运算符将实际对象,而不是引用作为参数).当然解决方案很明确:所有参数和方法都应该是const,甚至可能返回一个const对象或引用.不幸的是,这是不可能的,因为在操作过程中所涉及的任何物体都是不变的!这可能听起来很奇怪,但这是数学所涉及的不可避免的后果.我可以伪造它,使用const_cast,但代码仍然是错误的!

有没有办法解决这个问题?我目前唯一的解决方案是使返回对象为const,从而有效地禁用操作符链接.

问候,.jonas.

Ste*_*sop 5

如果你的对象是1GB(我猜他们在堆上分配的内存,而不是它们的实际sizeof大小),你可能不应该在它们上支持这些运算符.问题在于,运算符链接的示例或多或少地将不可变对象假定为"正在发生什么"的基本模型,并创建了许多临时值作为中间结果.您不能指望编译器能够有效地重用空间.但是你也无法随便复制1GB的物品.

相反,您应该只支持各种分配运算符.然后你的客户而不是写:

y = a * b + c;
Run Code Online (Sandbox Code Playgroud)

这可能会产生巨大的临时性,应该写:

// y = a * b + c
y = a;
y *= b;
y += c;
Run Code Online (Sandbox Code Playgroud)

这样,用户可以对事物保持封闭.很容易看出没有创建临时代码,你不会意外地编写一行需要18GB运行的简单代码.如果你想这样做:

y = a * b + c * d;
Run Code Online (Sandbox Code Playgroud)

那么你的代码必须明确注意这里需要一个临时结果(假设你不能删除a,b,c,d中的任何一个):

// y = a * b + c * d
y = a;
y *= b;
{
   FunctionTree x = c;
   x *= d;
   y += x;
}
Run Code Online (Sandbox Code Playgroud)

但是如果调用者碰巧知道例如在此之后不需要c,则可以明确地执行:

// y = a * b + c * d  [c is trashed]
c *= d;
y = a;
y *= b;
y += c;
Run Code Online (Sandbox Code Playgroud)

理论上,编译器可能会根据链式运算符的大表达式自行处理所有这些事情,并且数据流分析表明它c未被使用.对于整数运算来说,开启了大量优化的优秀编译器是很好的,所以机器就在那里.在实践中,我不会指望它.如果编译器无法证明FunctionTree的构造函数和析构函数没有可观察到的副作用,那么它跳过它们的能力仅限于标准中合法"复制省略"的特定情况.

或者您可以查看GMP的C接口,看看如何在没有运算符重载的情况下完成此操作.所有函数都采用"out参数",结果写入.因此,例如,如果x是一个巨大的多精度整数,你想要乘以10,你选择是否写:

mpz_mul_ui(x, x, 10); // modifies x in place, uses less memory
Run Code Online (Sandbox Code Playgroud)

要么:

mpz_t y;
mpz_init(y);
mpz_mul_ui(y, x, 10); // leaves x alone, result occupies as much memory again.
Run Code Online (Sandbox Code Playgroud)