Если ваши объекты имеют размер 1 ГБ (я полагаю, это память, которую они выделяют в куче, а не их фактический sizeof
размер), вы, вероятно, не должны поддерживать эти операторы на них. Проблема в том, что ваши примеры цепочки операторов более или менее предполагают неизменные объекты в качестве базовой модели «того, что происходит», и создают много временных объектов, которые служат промежуточными результатами. Вы не можете рассчитывать на то, что компилятор сможет эффективно использовать пространство. Но вы также не можете копировать объекты размером 1 ГБ, волей-неволей.
Вместо этого вы должны поддерживать только различные присваивающие операторы. Тогда ваш клиент вместо того, чтобы писать:
y = a * b + c;
, который может создавать огромные временные, должен вместо этого написать:
// y = a * b + c
y = a;
y *= b;
y += c;
Таким образом, пользователь может держать вещи под контролем. Легко видеть, что временные файлы не создаются, и вы не случайно напишите простую строку кода, для запуска которой требуется 18 ГБ. Если вы хотите сделать:
y = a * b + c * d;
тогда ваш код должен явно указать, что здесь требуется временный результат (при условии, что вы не можете удалить ни одну из a, b, c, d):
// y = a * b + c * d
y = a;
y *= b;
{
FunctionTree x = c;
x *= d;
y += x;
}
но если звонящий узнает, что, например, после этого c не нужен, вы можете явно сделать:
// y = a * b + c * d [c is trashed]
c *= d;
y = a;
y *= b;
y += c;
Теоретически, компилятор может решить все эти задачи для себя, основываясь на большом выражении с цепочечными операторами и анализе потока данных, чтобы показать, что c
не используется. Хорошие компиляторы с включенной оптимизацией хороши для целочисленной арифметики, так что механизм есть. На практике я бы на это не рассчитывал. Если компилятор не может доказать, что конструктор и деструктор FunctionTree не имеют видимых побочных эффектов, то его способность пропускать их ограничивается конкретными случаями юридического «исключения из копий» в стандарте.
Или вы можете посмотреть на интерфейс C к GMP, чтобы увидеть, как это делается без перегрузки оператора вообще. Все функции там принимают «параметр out», в который записывается результат. Так, например, если x
- это огромное целое число с кратной точностью, которое вы хотите умножить на 10, вы выбираете:
mpz_mul_ui(x, x, 10); // modifies x in place, uses less memory
или
mpz_t y;
mpz_init(y);
mpz_mul_ui(y, x, 10); // leaves x alone, result occupies as much memory again.