Russian Qt Forum
Ноябрь 23, 2024, 22:43 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Вопрос читаемости: передача класса в функцию по значению/конст. ссылке?  (Прочитано 10825 раз)
Akon
Гость
« : Апрель 24, 2011, 12:34 »

Пусть мы имеем достаточно большой класс, например Matrix (соответствующий математической матрице), т.е. копировать объекты данного класса лишний раз крайне не хотелось бы. Рассмотрим два варианта функции, отображающей матрицу в число, но перед отображением исходная матрица изменяется:

Код:
int func(const Matrix& matrix)
{
SomeClass temp = matrix;
temp.transform();            // каким-либо образом трансформирует матрицу
return matrix2Scalar(temp);  // каким-либо образом отображает матрицу в число
}

int func(Matrix matrix)
{
matrix.transform();            // каким-либо образом трансформирует матрицу
return matrix2Scalar(matrix);  // каким-либо образом отображает матрицу в число
}

Вариант 1 более ясный, поскольку вариант 2 смотрится как небрежный (банальный недосмотр, когда предполагается передача по конст. ссылке, а не по значению) и заставит заглянуть внутрь функции. С другой стороны, вариант 2 немного более лаконичен и оптимален в плане машинного кода.

Собственно, ваши мнения.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Апрель 24, 2011, 13:33 »

Вариант 2 (умышленная передача по значению) так или иначе неизбежен. Напр нужно инвертировать на месте
Код
C++ (Qt)
void MatrixInverse( Matrix * result, Matrix source );
...
MatrixInverse(&M, M);
 
Вполне ясно что in/out могут быть равны, а так
Код
C++ (Qt)
void MatrixInverse( Matrix * result, const Matrix & source );
 
Непонимающий  этой ясности нет
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #2 : Апрель 24, 2011, 13:39 »

Igors
не понял разницы
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Апрель 24, 2011, 13:54 »

Igors
не понял разницы
В последнем варианте можете ли Вы (увидев лишь прототип ф-ции) сказать могут ли result и source указывать на одну структуру? Думается что нет.

Хотя впрочем с Qt тут все подают и возвращают по значению (испакостили язык).
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Апрель 24, 2011, 15:27 »

а почему не могут? если ф-ия криво написана, то ее надо переписать
в qt передается по ссылке внутрь ф-ии.
Записан
blood_shadow
Гость
« Ответ #5 : Апрель 24, 2011, 16:24 »

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

нам необходимо с исходной матрицы построить новую:
Код
C++ (Qt)
int func(const Matrix& matrix)

необходимо изменить исходную матрицу:
Код
C++ (Qt)
void func(Matrix* matrix)

следуя такому принципу читателю будет не сложно понять, что делается в подобных
вызовах:

Код
C++ (Qt)
int det = func(matrix)
и
Код
C++ (Qt)
func(&matrix)
Записан
Akon
Гость
« Ответ #6 : Апрель 24, 2011, 19:35 »

Об изменении исходного объекта речи не идет.

Код:
...
Matrix matrix;
int transposedMatrixDeterminant = transposedMatrixDeterminant(matrix);  // определитель транспонир. матрицы
int originalMatrixDeterminant = determinant(matrix);  // определитель исходной матрицы
...

Каким будет прототип ф-ии transposedMatrixDeterminant()?
Записан
Fat-Zer
Гость
« Ответ #7 : Апрель 24, 2011, 20:18 »

на самом деле оба варианта равнозначны. Инстинктивно хочется выбрать первый, но тогда мы обманываем читающего, создавая впечатление, что матрица не копируется. С другой стороны, как уже говорили передача по значению матрицы выглядит неграмотной, хотя в данном случае она вполне уместна.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #8 : Апрель 24, 2011, 22:24 »

Хотя впрочем с Qt тут все подают и возвращают по значению (испакостили язык).

Хотелось бы увидеть кто это так пакостит и посмотреть результат этих пакостей )))

1. Передачу по ссылкам и указателям никто не отменял
2. см. Implicit Sharing
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Blackwanderer
Гость
« Ответ #9 : Апрель 25, 2011, 04:06 »

Если возникают подобные вопросы - в 99% случаев у вас неправильная структура классов/функций.
Код:
...
Matrix matrix;
Matrix transposed_matrix = matrix.transposed();
int transposedMatrixDeterminant = determinant(transposed_matrix);  // определитель транспонир. матрицы
int originalMatrixDeterminant = determinant(matrix);  // определитель исходной матрицы
...
int determinant(const Matrix& matrix);

Если вам нужно всего один раз посчитать определитель транспонированной матрицы - то нафига городить все эти сложности с лишней функцией. Если несколько раз - то вы экономите на операции транспонирования, т.к. она делается только один раз а не при каждом вызове transposedMatrixDeterminant.

Или вообще вот так, совсем без копирований:
Код:
...
Matrix matrix;
int transposedMatrixDeterminant = matrix.determinantTransposed();  // определитель транспонир. матрицы
int originalMatrixDeterminant = matrix.determinant();  // определитель исходной матрицы
...
class Matrix
{
public:
int determinant() const;
int determinantTransposed() const;
}
« Последнее редактирование: Апрель 25, 2011, 04:11 от Черный Странник » Записан
Fat-Zer
Гость
« Ответ #10 : Апрель 25, 2011, 04:35 »

а если там не транспонирование и детерминант, а что-то действительно сложное?

ЗЫ: плохой пример, при транспонировании определитель не изменяется))
Записан
Blackwanderer
Гость
« Ответ #11 : Апрель 25, 2011, 04:40 »

а если там не транспонирование и детерминант, а что-то действительно сложное?

В любом случае изменение параметра есть либо прямой, либо побочный результат действия функции. В первом случае передаем параметр либо по неконстантной ссылке либо по указателю, как кому нравится, во втором - по константной ссылке.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #12 : Апрель 25, 2011, 08:44 »

Цитата: Akon
С другой стороны, вариант 2 немного более лаконичен и оптимален в плане машинного кода.
В плане машинного кода, имхо, оба варианта одинаковы, т.к. и в первом и во втором будет делаться копирование matrix в стек.
Поэтому первый предпочтительнее. И не мешало бы сам метод сделать const.
Записан

Qt 5.11/4.8.7 (X11/Win)
Akon
Гость
« Ответ #13 : Апрель 25, 2011, 09:04 »

Цитировать
ЗЫ: плохой пример, при транспонировании определитель не изменяется))
Да, пример просто показной.

Цитировать
Если возникают подобные вопросы - в 99% случаев у вас неправильная структура классов/функций...
Здесь вопрос не дизайна, а стиля. Не понимайте пример с определителем матрицы буквально. Есть заданный класс и некоторый специализированный алгоритм его обработки, который разработчик класса не реализует как метод, поскольку алгоритм специализированный. Но в специализированном алгоритме требуется предварительно трансформировать исходный объект, и такая трансформация доступна через метод класса. Мы можем передать объект по значению и трансформировать его, или передать объект по конст. ссылке, создать копию и работать с ней. См. пример из первого поста.

Цитировать
В плане машинного кода, имхо, оба варианта одинаковы, т.к. и в первом и во втором будет делаться копирование matrix в стек.
Поэтому первый предпочтительнее. И не мешало бы сам метод сделать const.
В первом варианте присутствует дополнительна передача ссылки. Это, конечно, сущая мелочь, но все равно дополнительный машинный код. И это не метод, а свободная функция.
« Последнее редактирование: Апрель 25, 2011, 09:20 от Akon » Записан
Blackwanderer
Гость
« Ответ #14 : Апрель 25, 2011, 09:36 »

Мы можем передать объект по значению и трансформировать его, или передать объект по конст. ссылке, создать копию и работать с ней. См. пример из первого поста.
Копировать объект придется в любом случае, т.к. его изменение не является главным результатом работы подпрограммы (в противном случае проблемы вообще нету, передавайте по адресу и меняйте). Однако, как правило, алгоритм трансформации с порождением нового объекта НЕ МЕДЛЕННЕЕ чем последовательное копирование объекта и его трансформация. Объясню на примере матрицы. В зависимости от ее структуры копирование будет иметь сложность от O(1) до O(NxM), где NxM - размерность матрицы. Транспонирование матрицы имеет ту же сложность от O(1) до O(NxM). Итого, при передаче параметра по ссылке мы вызываем алгоритм сложности O(1) до O(NxM) один раз (копирование и трансформация совмещены), а при передаче по значению - два раза (первый раз при передаче в функцию, второй - при трансформации).
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.247 секунд. Запросов: 23.