передача по ссылке
От: nen777w  
Дата: 08.11.06 09:58
Оценка:
Смотрю чужой код...
Не пойму одну вещ какой смысл объявлять передачу по ссылке в ф-ции для переменных интегральных типов и выведенных из них (typedef), то же вопрос касается передачи по константному указателю (не принимая во внимания того что можно сделать const_cast).
Компилятор как то особо обрабатывает такие объявления?
Re: передача по ссылке
От: Константин Л. Франция  
Дата: 08.11.06 10:08
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Смотрю чужой код...

N>Не пойму одну вещ какой смысл объявлять передачу по ссылке в ф-ции для переменных интегральных типов и выведенных из них (typedef), то же вопрос касается передачи по константному указателю (не принимая во внимания того что можно сделать const_cast).
N>Компилятор как то особо обрабатывает такие объявления?

а что собенного в том, что интегральные типы передаются по ссылке? Может быть ты имел ввиду const&? По поводу const*. Это похоже на опциональный аргумент. Можно и NULL передать.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: передача по ссылке
От: np9mi7 Россия  
Дата: 08.11.06 11:15
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>а что собенного в том, что интегральные типы передаются по ссылке?


Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[2]: передача по ссылке
От: nen777w  
Дата: 08.11.06 11:20
Оценка:
КЛ>а что собенного в том, что интегральные типы передаются по ссылке? Может быть ты имел ввиду const&?
Да. Именно так, забыл указать. Если учеть то что кастов никаких с этой переменной в этом коде не проделывают.

КЛ>По поводу const*. Это похоже на опциональный аргумент. Можно и NULL передать.

Да, как то я об этом не подумал, просто сбило то что реально в коде этой ф-ции не допускают её работу с NULL.
Re[3]: передача по ссылке
От: night beast СССР  
Дата: 08.11.06 11:36
Оценка:
Здравствуйте, np9mi7, Вы писали:

КЛ>>а что собенного в том, что интегральные типы передаются по ссылке?


N>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


какие нибудь цифры, поддверждающие предположение имеются?
Re[3]: передача по ссылке
От: Константин Л. Франция  
Дата: 08.11.06 11:39
Оценка:
Здравствуйте, np9mi7, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>а что собенного в том, что интегральные типы передаются по ссылке?


N>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


это ты о чем?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: передача по ссылке
От: Константин Л. Франция  
Дата: 08.11.06 11:42
Оценка:
Здравствуйте, nen777w, Вы писали:

КЛ>>а что собенного в том, что интегральные типы передаются по ссылке? Может быть ты имел ввиду const&?

N>Да. Именно так, забыл указать. Если учеть то что кастов никаких с этой переменной в этом коде не проделывают.

лишняя попытка оптимизации?

КЛ>>По поводу const*. Это похоже на опциональный аргумент. Можно и NULL передать.

N>Да, как то я об этом не подумал, просто сбило то что реально в коде этой ф-ции не допускают её работу с NULL.

тогда не вижу смысла. еще одна лишняя попытка оптимизации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: передача по ссылке
От: nen777w  
Дата: 08.11.06 12:45
Оценка:
КЛ>>>а что собенного в том, что интегральные типы передаются по ссылке? Может быть ты имел ввиду const&?
N>>Да. Именно так, забыл указать. Если учеть то что кастов никаких с этой переменной в этом коде не проделывают.
КЛ>лишняя попытка оптимизации?
КЛ>>>По поводу const*. Это похоже на опциональный аргумент. Можно и NULL передать.
N>>Да, как то я об этом не подумал, просто сбило то что реально в коде этой ф-ции не допускают её работу с NULL.
КЛ>тогда не вижу смысла. еще одна лишняя попытка оптимизации?

Ну так это я вопрос задал ок. спишем на какую то мега задумку код писавшего или на невысыпон, вот как у меня сегодня прям
Re[4]: передача по ссылке
От: np9mi7 Россия  
Дата: 09.11.06 21:16
Оценка:
Здравствуйте, night beast, Вы писали:

N>>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


NB>какие нибудь цифры, поддверждающие предположение имеются?


В своей практике ни разу не встречал что замена функции вида
void f (const some_fundamental_type & value);
на
void f (some_fundamental_type value);
давала ощутимый прирост производительности. Но опираясь на классиков Andrei Alexandrescu хочу процитировать отрывок из его книги:

Modern C++ Design: Generic Programming and Design Patterns Applied
Chapter 2. Techniques
2.10.3 Optimized Parameter Types

In template code, you sometimes need to answer the following question: Given an arbitrary type T, what is
the most efficient way of passing and accepting objects of type T as arguments to functions? In general, the
most efficient way is to pass elaborate types by reference and scalar types by value. (Scalar types consist of
the arithmetic types described earlier as well as enums, pointers, and pointers to members.) For elaborate
types you avoid the overhead of an extra temporary (constructor-plus-destructor calls), and for scalar types
you avoid the overhead of the indirection resulting from the reference
.

, так что не знаю кому верить: небольшому опыту или классикам. Для себя решил — нет константных ссылок на фундаментальные типы;
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[4]: передача по ссылке
От: np9mi7 Россия  
Дата: 09.11.06 21:19
Оценка:
Здравствуйте, Константин Л., Вы писали:

N>>Тратиться дополнительное время на один уровень косвенности


КЛ>это ты о чем?


Это об операции разъименования (получения значения по ссылке);
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[5]: передача по ссылке
От: night beast СССР  
Дата: 10.11.06 04:58
Оценка:
Здравствуйте, np9mi7, Вы писали:

N>>>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


NB>>какие нибудь цифры, поддверждающие предположение имеются?


N>В своей практике ни разу не встречал что замена функции вида

N>
N>void f (const some_fundamental_type & value);
N>
на

N>
N>void f (some_fundamental_type value);
N>
давала ощутимый прирост производительности. Но опираясь на классиков Andrei Alexandrescu хочу процитировать отрывок из его книги:

N>так что не знаю кому верить: небольшому опыту или классикам. Для себя решил — нет константных ссылок на фундаментальные типы;

верить надо цифрам тестов

теоретически Александреску может и прав, но компиляторы должны уметь оптимизировать это дело.
и не известно, какой вариант более предпочтителен для оптимизации.
Re[5]: передача по ссылке
От: Erlond Россия  
Дата: 10.11.06 06:07
Оценка: -1
Здравствуйте, np9mi7, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


N>>>Тратиться дополнительное время на один уровень косвенности


КЛ>>это ты о чем?


N>Это об операции разъименования (получения значения по ссылке);

Ссылки не разименовываются, разыменовываются указатели, а ссылка — это просто просто "псевдоним", другое название той же переменной. Ссылка представляет собой адрес в памяти, начиная с которого лежат данные.
Re[6]: передача по ссылке
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 10.11.06 06:22
Оценка:
Здравствуйте, Erlond, Вы писали:

E>Ссылки не разименовываются, разыменовываются указатели, а ссылка — это просто просто "псевдоним", другое название той же переменной. Ссылка представляет собой адрес в памяти, начиная с которого лежат данные.


Почему тогда дизассемблер показывает две абсолютно идентичные функции:
void f(int *i)
{
    *i = 5;
}

void f(int &i)
{
    i = 6;
}

int main()
{
    int k(0);
    f(k);
    f(&k);

    return 0;
}
Re: передача по ссылке
От: Erlond Россия  
Дата: 10.11.06 06:30
Оценка: -1 :))
Здравствуйте, nen777w, Вы писали:

N>Смотрю чужой код...

N>Не пойму одну вещ какой смысл объявлять передачу по ссылке в ф-ции для переменных интегральных типов и выведенных из них (typedef), то же вопрос касается передачи по константному указателю (не принимая во внимания того что можно сделать const_cast).
N>Компилятор как то особо обрабатывает такие объявления?

Есть 3 способа передавать аргументы в функцию:

1). по значению;
2). по ссылке;
3). по указателю.

В 1-м случае создаётся временный объект, в который копируется значение аргумента, и функция работает с временным объектом. Внутри функции значения переданных аргументов можно изменять, это изменение никак не отразится за пределами функции. Недостаток — непроизводительные потери на создание временного объекта и копирование данных, что может быть достаточно накладно при больших объёмах.

Во 2-м случае функция получает адрес объекта и работает с ним напрямую, поэтому изменение значения аргумента, переданного функции по ссылке, будут видны за пределами функции. Это можно устранить, объявив ссылку константной. Достоинство — не происходит создания временного объекта и копирования даннных.

В 3-м случае почти то же самое, что и во 2-м, передаётся только указатель на данные, создания временного объекта не происходит. Отличия — указатель может быть NULL, при обращении к данным требуется операция разыменования (косвенная адресация).
Re[7]: передача по ссылке
От: Erlond Россия  
Дата: 10.11.06 06:35
Оценка:
Я думаю, что компилятор просто соптимизировал ассемлерный код, этот пример достаточно прост. Кстатии вполне вероятно, что переменной к вообще не создаётся, компилятор заменил её на константу, т.к. она не изменяет своего значения.
Re[8]: передача по ссылке
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 10.11.06 07:08
Оценка:
Здравствуйте, Erlond, Вы писали:

E>Я думаю, что компилятор просто соптимизировал ассемлерный код, этот пример достаточно прост. Кстатии вполне вероятно, что переменной к вообще не создаётся, компилятор заменил её на константу, т.к. она не изменяет своего значения.


Что значин "не изменяет своего значения"? Изменяет и ещё как (пример, вроде, достаточно простой, чтобы в нём разобраться). Она существует и создаётся.

Я, вообще, всегда думал, что передача по ссылке и по указателю физически представляет собой одно и тоже. Разница только в синтаксисе.
Re[9]: передача по ссылке
От: Erlond Россия  
Дата: 10.11.06 08:04
Оценка: -2
Здравствуйте, Nuzhny, Вы писали:

N>Здравствуйте, Erlond, Вы писали:


E>>Я думаю, что компилятор просто соптимизировал ассемлерный код, этот пример достаточно прост. Кстатии вполне вероятно, что переменной к вообще не создаётся, компилятор заменил её на константу, т.к. она не изменяет своего значения.


N>Что значин "не изменяет своего значения"? Изменяет и ещё как (пример, вроде, достаточно простой, чтобы в нём разобраться). Она существует и создаётся.


N>Я, вообще, всегда думал, что передача по ссылке и по указателю физически представляет собой одно и тоже. Разница только в синтаксисе.


Согласен, изменяет, это я спросони напутал.
Передача аргумента по ссылке и по указателю — это разные вещи. Ссылка это просто адрес объекта, а указатель — это "ячейка", где хранится адрес объекта.
Re[2]: передача по ссылке
От: demi США  
Дата: 10.11.06 08:18
Оценка:
Здравствуйте, Erlond, Вы писали:

E>Здравствуйте, nen777w, Вы писали:


E>В 3-м случае почти то же самое, что и во 2-м, передаётся только указатель на данные, создания временного объекта не происходит. Отличия — указатель может быть NULL, при обращении к данным требуется операция разыменования (косвенная адресация).


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

int foo = 0;
int bar = 10;

int* p1 = NULL;
int* p2 = &foo;
p1 = p2; //Pointer changed

int& r1 = foo;
int& r2 = bar;
r1 = r2; 
//Now 'foo' == 10, 'bar' == 0


Ну и синтаксис конечно. Ссылки не инициализипуются (синтаксически) если они параметры функции. Введение их — стремление немного обезопасить C++. Врядли они сильно помогают при оптимизации, кроме как cons T& в ситауциях типа:

class T
{
  //Pretty heavy definition
};

void f1(const T* p);
void f2(const T& p);

void f()
{
  f1(&T()); //Error
  f2( T()); //Ok
}
Не стыдно попасть в дерьмо, стыдно в нём остаться!
Re[5]: передача по ссылке
От: Константин Л. Франция  
Дата: 10.11.06 09:25
Оценка:
Здравствуйте, np9mi7, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


N>>>Тратиться дополнительное время на один уровень косвенности


КЛ>>это ты о чем?


N>Это об операции разъименования (получения значения по ссылке);


ссылку, подтверждающую слова и тот факт, что копирование дешевле этой операции (если она действительно сущ.)?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: передача по ссылке
От: Константин Л. Франция  
Дата: 10.11.06 11:07
Оценка:
Здравствуйте, demi, Вы писали:

ну ссылку на источник уже пока привести.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: передача по ссылке
От: Кодт Россия  
Дата: 10.11.06 16:44
Оценка: 17 (2)
Здравствуйте, night beast, Вы писали:

NB>теоретически Александреску может и прав, но компиляторы должны уметь оптимизировать это дело.

NB>и не известно, какой вариант более предпочтителен для оптимизации.

Передача по значению всё-таки предпочтительнее.
Пример:
extern void xxx();

void foo(int n)
{
    for(int i=0; i<n; ++i)
        xxx();
}

void bar(int const& n)
{
    for(int i=0; i<n; ++i)
        xxx();
}

/////////////////////////////

int global_n;
void xxx()
{
    --global_n;
}

int main()
{
    global_n = 100; foo(global_n);
    global_n = 100; bar(global_n);
}

В случае foo компилятор может установить, что на n (как и на i) нет никакого влияния извне, и сделать цикл от 0 до n так, как удобнее (например, с обратным отсчётом)
В случае bar таких гарантий нет (возможна ситуация, как xxx + main под чертой), и поэтому нужно перечитывать n на каждой итерации.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[7]: передача по ссылке
От: Константин Л. Франция  
Дата: 10.11.06 17:02
Оценка:
Здравствуйте, Кодт, Вы писали:

[]

К>В случае foo компилятор может установить, что на n (как и на i) нет никакого влияния извне, и сделать цикл от 0 до n так, как удобнее (например, с обратным отсчётом)

К>В случае bar таких гарантий нет (возможна ситуация, как xxx + main под чертой), и поэтому нужно перечитывать n на каждой итерации.

Это может произойти только в многопоточном окружении. Разве компилятор должен рассматривать такой случай?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: передача по ссылке
От: night beast СССР  
Дата: 11.11.06 11:26
Оценка:
Здравствуйте, Кодт, Вы писали:

NB>>теоретически Александреску может и прав, но компиляторы должны уметь оптимизировать это дело.

NB>>и не известно, какой вариант более предпочтителен для оптимизации.

К>Передача по значению всё-таки предпочтительнее.

К>Пример:
К>В случае foo компилятор может установить, что на n (как и на i) нет никакого влияния извне, и сделать цикл от 0 до n так, как удобнее (например, с обратным отсчётом)
К>В случае bar таких гарантий нет (возможна ситуация, как xxx + main под чертой), и поэтому нужно перечитывать n на каждой итерации.

Пример не совсем корректен, поскольку функции делают разные вещи, однако идею уловил. Спасибо.

В реальной ситуации по прежнему больше доверяю тестам
Re: Если уж сильно хочется...
От: Roman Odaisky Украина  
Дата: 11.11.06 12:08
Оценка:
template <class T>
inline void foo(T const& value)
{
    fooImpl<T>(value);
}

template <class T>
void fooImpl(boost::call_traits<T>::param_type value)
{
    . . .
}

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

Premature optimization is the root of all evil, помните!
До последнего не верил в пирамиду Лебедева.
Re[2]: передача по ссылке
От: remark Россия http://www.1024cores.net/
Дата: 11.11.06 16:34
Оценка:
Здравствуйте, Erlond, Вы писали:

E>Есть 3 способа передавать аргументы в функцию:


E>1). по значению;

E>2). по ссылке;
E>3). по указателю.

E>В 1-м случае создаётся временный объект, в который копируется значение аргумента, и функция работает с временным объектом. Внутри функции значения переданных аргументов можно изменять, это изменение никак не отразится за пределами функции. Недостаток — непроизводительные потери на создание временного объекта и копирование данных, что может быть достаточно накладно при больших объёмах.


E>Во 2-м случае функция получает адрес объекта и работает с ним напрямую, поэтому изменение значения аргумента, переданного функции по ссылке, будут видны за пределами функции. Это можно устранить, объявив ссылку константной. Достоинство — не происходит создания временного объекта и копирования даннных.


E>В 3-м случае почти то же самое, что и во 2-м, передаётся только указатель на данные, создания временного объекта не происходит. Отличия — указатель может быть NULL, при обращении к данным требуется операция разыменования (косвенная адресация).


Врменный объект создаётся всегда. Просто во втором и третем случаях временный объект — указатель. Соответственно, если размер объекта не больше размера указателя, то время на передачу одинаковое.
Во втором и третьем случае разыменование происходит одинакого.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: передача по ссылке
От: HiSH Россия http://m0riarty.ya.ru
Дата: 13.11.06 08:25
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, np9mi7, Вы писали:


КЛ>>>а что собенного в том, что интегральные типы передаются по ссылке?


N>>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


NB>какие нибудь цифры, поддверждающие предположение имеются?


#include <iostream>

using namespace std;

int foo(int n){
        if (n > 1)
                return n * foo(n - 1);
        else
                return 1;
}

int boo(const int& n){
        if (n > 1)
                return n * boo(n - 1);
        else
                return 1;
}

int main(int argc, char** argv){
        cout << "sizeof(int): " << sizeof(int) << endl;
        cout << "sizeof(const int&): " << sizeof(const int&) << endl;
        if (argc == 2){
                if (argv[1][0] == '1'){
                        cout << "by value" << endl;
                        for (int i = 0; i < 10000000; i++)
                                foo(30);
                }
                if (argv[1][0] == '2'){
                        cout << "by const &" << endl;
                        for (int i = 0; i < 10000000; i++)
                                boo(30);
                }
        }
}



moriarty@earthquake:~$ time ./a.out 1
sizeof(int): 4
sizeof(const int&): 4
by value

real 0m2.705s
user 0m2.704s
sys 0m0.004s


moriarty@earthquake:~$ time ./a.out 2
sizeof(int): 4
sizeof(const int&): 4
by const &

real 0m3.056s
user 0m3.048s
sys 0m0.008s



moriarty@earthquake:~$ gcc --version
gcc (GCC) 4.0.3 (Ubuntu 4.0.3-1ubuntu5)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


"И все-таки, она вертится"
Re[8]: передача по ссылке
От: Кодт Россия  
Дата: 13.11.06 08:33
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Это может произойти только в многопоточном окружении.


Неправда. Мой пример однопоточный, и в нём всё происходит.

КЛ> Разве компилятор должен рассматривать такой случай?


Компилятор не имеет права оптимизировать работу с переменными, которые могут быть доступны под другим именем.

Вот ещё один пример
int x = 0;
int *p = &x;
int i, n; // в этом месте переменные i и n строго локальны

for(i=0, n=10; i!=n; ++i) // и поэтому их можно разместить в регистрах
    --*p;                 // а то и вообще развернуть цикл

if(rand()%2)
    p = &n;
// начиная с этого места n может меняться извне
for(i=0, n=10; i!=n; ++i)
    --*p;
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: передача по ссылке
От: SWW Россия  
Дата: 13.11.06 11:01
Оценка:
R>Врменный объект создаётся всегда. Просто во втором и третем случаях временный объект — указатель. Соответственно, если размер объекта не больше размера указателя, то время на передачу одинаковое.

Время работы конструктора намного больше, чем время пересылки байтов. Поэтому double лучше передавать по значению, а CString — по ссылке, несмотря на то, что ее размер равен размеру указателя.

R>Во втором и третьем случае разыменование происходит одинакого.


Re[5]: передача по ссылке
От: night beast СССР  
Дата: 13.11.06 12:44
Оценка:
Здравствуйте, HiSH, Вы писали:

КЛ>>>>а что собенного в том, что интегральные типы передаются по ссылке?


N>>>Тратиться дополнительное время на один уровень косвенности, а памяти отъедает меньше чем фактический тип только в случае long long;


NB>>какие нибудь цифры, поддверждающие предположение имеются?


HSH>moriarty@earthquake:~$ time ./a.out 1

HSH>real 0m2.705s
HSH>user 0m2.704s
HSH>sys 0m0.004s


HSH>moriarty@earthquake:~$ time ./a.out 2
HSH>real 0m3.056s
HSH>user 0m3.048s
HSH>sys 0m0.008s



HSH>"И все-таки, она вертится"


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