Я пытаюсь написать векторный класс C++, который хранит массив данных и позволяет выполнять математические операции поэтапно. Я хочу реализовать это так, что выражение a = b + c + d
должно циклически перебирать все элементы только один раз и напрямую записывать сумму b[i] + c[i] + d[i]
в a[i]
без создания промежуточных векторов.Эффективные векторные операторы в C++/Ссылки на временные объекты
я писал что-то вроде этого:
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
}
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
T& operator[] (int i) { return data[i]; }
T& const operator[] (int i) const { return data[i]; }
MyVector<T,N>& operator=(const VectorExpression<T,N> &rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
}
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
VectorExpression<T,N> &a, &b;
public:
VectorSum(VectorExpression<T,N> &aa, VectorExpression<T,N> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
}
template<class T, int N>
VectorSum<T,N> operator+(const VectorExpression<T,N> &a,
const VectorExpression<T,N> &b)
{
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,10> a, b, c, d;
// Initialize b, c, d here
a = b + c + d;
return 0;
}
Вероятно, эта функциональность обеспечивается классом valarray, но это потому, что я пытался лишить его до минимального примера.
Я сделал operator[]
виртуальный, потому что это позволяет вложенности все виды выражений (например a = !(-b*c + d)
) при условии, я бы определить все операторы и соответствующие классы, аналогичные VectorSum
.
Я использую ссылки, потому что обычные переменные не являются полиморфными, а указатели не работают с перегрузкой оператора.
Теперь мои вопросы по этому поводу являются:
В заявлении
a = b + c + d;
два временныхVectorSum<double,10>
объекты будут созданы для храненияb + c
и(b+c) + d
соответственно. Будут ли они жить достаточно долго, чтобы заставить полиморфное поведение работать? Более конкретно,(b+c) + d
сохранит ссылку наb + c
, но будет ли этот объект еще существовать, когда вызываетсяoperator=
? Согласно this post все временные файлы должны существовать до тех пор, покаoperator=
не вернется, но это также относится к более старым версиям C++?Если нет, то как это делается? Единственная альтернатива, которую я вижу, заключается в том, чтобы выделить объекты
VectorSum
с использованиемnew
, вернуть их по ссылке, а затем удалить их в функцияхoperator=
, но это кажется немного громоздким и, вероятно, намного менее эффективным. Я также не уверен, что это всегда безопасно.(Minor вопрос) Можно ли переопределить тип возвращаемого
T
изVectorExpression::operator[]
поT& const
вMyVector
?
EDIT
Я имел неправильные типы аргументов в операторе +: изменил их от VectorSum
к VectorExpression
.
Это не отвечает на ваши вопросы, и я не стал глубоко заглядывать в ваш код, но я не уверен, что это способ добиться эффективной оценки вашей суммы. Рассматривали ли вы использование [шаблонов выражения] (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template)? – coincoin
Насколько я понимаю, сайт, на который вы ссылаетесь, делает более или менее то же самое, что и я, за исключением использования шаблонов вместо наследования. Я не думал об этом, так что спасибо. Я не очень уверен, какой вариант лучше; их методу не нужны виртуальные классы, но для этого требуется гораздо больше классов (особенно если вы считаете их после создания экземпляра), а временные объекты всех этих классов должны быть созданы. – PieterNuyts
Это может быть интересно вам: http://stackoverflow.com/q/11809052/1116364 –