С++ для начинающих


         

и не стало частью языка,


Matrix c = a + b;

было бы трансформировано в

Matrix c;

operator+(c, a, b);

Это расширение так и не стало частью языка, но предложенная оптимизация прижилась. Компилятор в состоянии распознать, что возвращается объект класса и выполнить трансформацию его значения и без явного расширения языка. Если дана функция общего вида:

classType

functionName( paramList )

{

   classType namedResult;

   // выполнить какие-то действия ...

   return namedResult;

}

то компилятор самостоятельно трансформирует как саму функцию, так и все обращения к ней:

void

functionName( classType &namedResult, paramList )

{

   // вычислить результат и разместить его по адресу namedResult

}

что позволяет уйти от необходимости возвращать значение объекта и вызывать копирующий конструктор. Чтобы такая оптимизация была применена, в каждой точке возврата из функции должен возвращаться один и тот же именованный объект класса.

И последнее замечание об эффективности работы с объектами в C++. Инициализация объекта класса вида

Matrix c = a + b;

всегда эффективнее присваивания. Например, результат следующих двух инструкций такой же, как и в предыдущем случае:

Matrix c;

c = a + b;

но объем требуемых вычислений значительно больше. Аналогично эффективнее писать:

for ( int ix = 0; ix < size-2; ++ix ) {

     Matrix matSum = mat[ix] + mat[ix+1];

     // ...

}

чем

Matrix matSum;

for ( int ix = 0; ix < size-2; ++ix ) {

     matSum = mat[ix] + mat[ix+1];

     // ...

}

Причина, по которой присваивание всегда менее эффективно, состоит в том, что возвращенный локальный объект нельзя подставить вместо объекта в левой части оператора присваивания. Иными словами, в то время как инструкцию

Point3d p3 = operator+( p1, p2 );

можно безопасно трансформировать:

// Псевдокод на C++

Point3d p3;

operator+( p3, p1, p2 );

преобразование

Point3d p3;

p3 = operator+( p1, p2 );

в

// Псевдокод на C++

// небезопасно в случае присваивания

operator+( p3, p1, p2 );

небезопасно.

Преобразованная функция требует, чтобы переданный ей объект представлял собой неформатированную область памяти. Почему? Потому что к объекту сразу применяется конструктор, который уже был применен к именованному локальному объекту. Если переданный объект уже был сконструирован, то делать это еще раз с семантической точки зрения неверно.


Содержание  Назад  Вперед