Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.50/56: Рейтинг темы: голосов - 56, средняя оценка - 4.50
47 / 21 / 11
Регистрация: 01.11.2013
Сообщений: 255
1

Как лучше передавать аргумент в функцию - по ссылке или по указателю?

30.01.2016, 20:31. Показов 10517. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Предположим, что нам нужно в функцию передать значение переменной чтобы по окончанию работы функции значение переменной изменилось. Меня интересует, что лучше использовать если мы знаем название переменной, ссылку или указатель? И что будет эффективнее? Мне кажется, что ссылка будет лучше, так как для указателя нужно выделять память чтобы он хранил адрес переменной. Но все используют указателя, а не ссылки.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.01.2016, 20:31
Ответы с готовыми решениями:

Передача в функцию по ссылке или указателю
Гуру C++, как предпочтительнее делать?:) void f1(int &a) { a = 5; } void f2(int *...

Передача параметров в функцию по значению, по ссылке или по указателю
Передача параметров в функцию по значению, по ссылке или по указателю. Чем отличаются эти 3...

Зачем при перегрузке инкремента дружественной функцией передавать аргумент по ссылке?
В программе реализованы два инкремента: префиксный и постфиксный. Зачем в функции передавать...

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

20
Модератор
Эксперт CЭксперт С++
5286 / 2373 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
30.01.2016, 20:32 2
maks242, ссылку проще. Разыменовывать не надо.
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
30.01.2016, 20:36 3
Используй ссылку. Она для этого и создана.
0
634 / 389 / 75
Регистрация: 21.09.2008
Сообщений: 1,330
30.01.2016, 20:48 4
maks242, чтобы не "гадать на кофейной гуще", сгенерируйте компилятором ассемблерный листинг и сравните вызовы. Делов-то.
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
30.01.2016, 20:49 5
Лучший ответ Сообщение было отмечено maks242 как решение

Решение

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

однако, в наши дни это уже не актуально.
современные компиляторы прекрасно оптимизируют и ссылки,
и указатели.

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

например, потому что ссылки не нужно проверять на валидность.
один лишь этот фактор делает код с ссылками более эффективным.

Цитата Сообщение от maks242 Посмотреть сообщение
Мне кажется, что ссылка будет лучше, так как для указателя нужно выделять память чтобы он хранил адрес переменной.
об этом не нужно переживать.
если компилятору не доступен контекст использования ссылки,
то он реализует её через механизм указателя.

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

Цитата Сообщение от maks242 Посмотреть сообщение
Но все используют указателя, а не ссылки.
не знаю, кто такие "все".

грамотные люди используют ссылки там,
где ожидается работа с реальным (валидным) объектом.

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

"указатели во все поля" - так делают либо совсем зеленые новички,
либо сишники, которые так и не осилили плюсы,
либо "священаы воены", которые любят кушать свой кактус,
либо просто балбесы.
3
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
30.01.2016, 20:57 6
Цитата Сообщение от hoggy Посмотреть сообщение
"указатели во все поля" - так делают либо совсем зеленые новички,
либо сишники, которые так и не осилили плюсы,
либо "священаы воены", которые любят кушать свой кактус,
либо просто балбесы.
да я такой)))

И да я не использую ссылки т.к. при вызове не понятно будет ли изменён объект, и ссылку не переназначишь если надо изменить поведение в процессе.
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
30.01.2016, 20:57 7
Цитата Сообщение от sharpey Посмотреть сообщение
чтобы не "гадать на кофейной гуще" ...
Здесь не нужно гадать. Ссылка однозначно подходит лучше.
2
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
30.01.2016, 21:00 8
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
т.к. при вызове не понятно будет ли изменён объект
C++
1
2
void change(data& target);
void view(const data& target);
вам действительно не очевидно, в каком случае цель будет изменена?

может быть вот так вам будет более очевидно?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
struct data { int v = 0; };
 
void view(const data& target)
{
    // error: assignment of member ‘data::v’ in read-only object
    target.v = 33; 
    std::cout << "v = "<< target.v << '\n';
}
 
int main()
{
    std::cout << "Hello, world!\n";
}
2
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
30.01.2016, 21:45 9
hoggy, вы сейчас о чём?

Я о холливаре где обсуждается
C++
1
2
3
int a = 10;
f(a); // f(&a); easy to propose of changing
// is a still equal 10 ?
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
30.01.2016, 22:23 10
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
ссылку не переназначишь если надо изменить поведение в процессе.
ссылка в принципе не подходит для случаев,
когда нужно перенацеливаться.

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Я о холливаре где обсуждается
int a = 10;
f(a); // f(&a); easy to propose of changing
// is a still equal 10 ?
это - бессмысленный холивар.

http://rextester.com/PYMJNF60861

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <cassert>
 
void f(const int* p)
{
    // если нам нужен качественный, стабильный софт
    // то с указателями, мы вынуждены писать дополнительный проверочный код
    assert(p); 
 
    // а так же подумать о сопутствующем падении производительности
    // если нам нужна отказоустойчивость
    if(!p)
        throw std::runtime_error("expected valid pointer");
    
    std::cout<<"read-only: " << *p << std::endl; 
}
 
void b(int* p)
{
    assert(p);
    std::cout<<"before: "<< *p <<'\n'; 
    *p = 33;
    std::cout<<"change: " << *p << '\n'; 
}
 
int main()
{
    std::cout << "Hello, world!\n";
   
    int a = 10;
 
    // как глядя на одно лишь использование
    // и не зная прототипов,
    // вы определите какая из функций меняет значение, а какая нет?
    f(&a);
    b(&a);
}
на языке с++ контракты задаются прототипами.
не зная прототипа, вы не можете с 100% уверенностью сказать,
какие гарантии даёт вам функция.

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

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

нотация берет свои корни из языка си, который не умеет ссылки,
но хочет модифицировать указатели

на языке с++ это выглядит так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <cassert>
 
void change(int*& p ) //<--- воздействуем на оригинальный указатель
{      // а не на копию
    delete p;
    p = new int(2);
    assert(p);
}
 
int main()
{
    std::cout << "Hello, world!\n";
    
    int* p = new int(1);
    
    assert(p);
    
    std::cout << "value = "<< *p << '\n';
    change(p);
    
    assert(p);
    std::cout << "value = "<< *p << '\n';
}

однако, сишка ссылки не умеет,
и поэтому, там приходилось делать так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Title of this code
//gcc 4.9.2
 
#include <stdio.h>
#include <assert.h>
 
 
void change(int** p )
{
    assert(p);
    assert(*p);
 
    free(*p);
    realloc (*p, sizeof(int)); 
    assert(p);
    **p = 2;
}
 
int main(void)
{
    printf("Hello, world!\n");
    
    int* p = malloc(sizeof(int));
    *p = 1;
        
    assert(p);    
    printf("value = %d \n", *p);
    
    change(&p);
    
    assert(p);
    printf("value = %d \n", *p);
    
    return 0;
}
обратите внимание: указатель им приходилось передавать как двойной,
что бы иметь возможность воздействовать на оригинальный указатель.
на сишке просто нет иного способа, что бы поиметь желаемый профит.

однако на плюсах все гораздо проще.
и здесь такая нотация просто не актуальна.
1
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
30.01.2016, 22:53 11
Цитата Сообщение от hoggy Посмотреть сообщение
ссылка в принципе не подходит для случаев,
когда нужно перенацеливаться.
так и я о чём? Гибкость -)

Цитата Сообщение от hoggy Посмотреть сообщение
это - бессмысленный холивар.
да они все лишены смысла)

Цитата Сообщение от hoggy Посмотреть сообщение
граммар конст
а на англ как? не могу загуглить, что за идеалогия такая. Только ваш холиварчик нашёл с Avazart`ом тыц

Итого я то и сам использую const T& но есть же ж случаи когда я делаю &name - к своему стыду и малому опыту не могу навести сейчас пример, но он ведь есть же ж)
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
30.01.2016, 23:34 12
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
так и я о чём? Гибкость -)
гибкость ради гибкости не нужна.
гибкость нужна лишь там,
где это объективно необходимо:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
// псевдокод
struct child
{
    child(parent& p)  //<--- принимает по ссылке,
        : m_parent(p)   // потому что ожидает реального
   {}            // валидного папочку
 
    ...
 
    parent& m_parent; //<--- ребенок гарантирует, 
      // что никогда  не поменяет своего родителя
 
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
// псевдокод
struct child
{
    child(parent& p)  //<--- ожидает что родитель - валидный объект
        : m_parent(&p)      // поэтому принимает по ссылке
   {}
 
   ...
 
    parent* m_parent; //<--- ребенок дает понять,
      // что не только может поменять родителя
      // но и вовсе остаться сиротой
};
технически, гибкости в плюсах на любые фантазии хватит.
вопрос лишь в цене, и в целесообразности.

если ожидается живой объект - проще и дешевле использовать ссылку.

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

Добавлено через 2 минуты
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
а на англ как?
а хз

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
не могу загуглить, что за идеалогия такая.
если вкратце: const во все поля.

если объект предназначен только для чтения,
то он должен быть const

если функция-член не изменяет состояние объекта,
а выполняется только в режиме для чтения,
то она должна быть const.

вроде бы Маерс писал, если не ошибаюсь:
"все, что может быть const, должно быть const"
2
Модератор
Эксперт CЭксперт С++
5286 / 2373 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
31.01.2016, 09:34 13
Цитата Сообщение от hoggy Посмотреть сообщение
вроде бы Маерс писал, если не ошибаюсь:
"все, что может быть const, должно быть const"
Он самый. Из книги "Эффективное использование C++ - 55 верных советов" (3-е издание, 2006):
Цитата Сообщение от Скотт Мейерс
Правило 3: Везде, где только можно, используйте const
Добавлено через 8 минут
У Макконнелла в книге "Совершенный код" (10.3. Принципы инициализации переменных):
Цитата Сообщение от Стив Макконнелл
Объявляйте переменные по мере возможности как final или const
Объявив переменную как final в Java или const в C++, вы можете предотвратить изменение ее значения после инициализации. Ключевые слова final и const полезны для определения констант класса, исключительно входных параметров и любых локальных переменных, значения которых должны оставаться неизменными после инициализации.
0
Неэпический
18099 / 10685 / 2061
Регистрация: 27.09.2012
Сообщений: 26,897
Записей в блоге: 1
31.01.2016, 11:48 14
Цитата Сообщение от hoggy Посмотреть сообщение
вроде бы Маерс писал, если не ошибаюсь:
"все, что может быть const, должно быть const"
только вот в новой книге, он ясно дает понять, что
C++
1
void foo(const ClassType obj)
не особо хорошая идея, т.к. помешает перемещению.
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.01.2016, 12:03 15
Цитата Сообщение от Croessmah Посмотреть сообщение
только вот в новой книге, он ясно дает понять, что
void foo(const ClassType obj)
плохая идея.
идея дает:
+1 к защите от изменений изнутри функции

и в то же время:
+1 к синтаксическому мусору:

http://rextester.com/JWUX61217

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Title of this code
//g++  4.9.2
 
#include <iostream>
 
struct example{};
 
void foo(const example);
void bar(example);
 
int main()
{
    std::cout << "Hello, world!\n";
    
    typedef decltype( &foo )
        foo_t;
    
    typedef decltype( &bar )
        bar_t;
    
    const bool same = std::is_same<foo_t, bar_t>::value;
    
    std::cout <<"is same types? " 
        << (same ? "yes": "no" ) 
        << '\n';
}
Маерс считает, что различия в синтаксисе
идентичного по факту типа только запутывают.

о защите от изменений изнутри функции,
он как то не упомянул.
0
Неэпический
18099 / 10685 / 2061
Регистрация: 27.09.2012
Сообщений: 26,897
Записей в блоге: 1
31.01.2016, 12:11 16
hoggy, а теперь вдруг, мы решили переместить объект типа example (назовем его obj) в функции foo.
Простой std::move(obj) уже не прокатит,
т.к. врядли в example есть констуктор example(const example&&)
Соответственно, придется либо менять тип параметра, убирая const,
а это приведет к необходимости изменения клиентского кода,
а можно требовать у клиента вышеуказанного конструктора, что тоже крайне убого,
либо к снятию const у obj, в данном, случае, это, наверное,
самое лучшее решение будет.
Но тогда возникает вопрос,
на кой черт этот const вообще поставили изначально.
То есть он нам тупо может мешать в будущем, Вот я к чему
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.01.2016, 12:23 17
Цитата Сообщение от Croessmah Посмотреть сообщение
а теперь вдруг, мы решили переместить объект типа example (назовем его obj) в функции foo.
const в прототипе именно для того и существует,
что бы накорню пресекать подобные действия.

Цитата Сообщение от Croessmah Посмотреть сообщение
Но тогда возникает вопрос,
на кой черт этот const вообще поставили изначально.
строгие гарантии, за которыми следит компилятор.

строгие гарантии нужны для обеспечения отказоустойчивости системы.

но предоставить их может лишь тот функционал,
который гарантирует,
что в случае каких то поломок,
всегда можно откатиться взад.
так, словно вызова функции,
приведшего к аварии "как бы и не было".
0
Неэпический
18099 / 10685 / 2061
Регистрация: 27.09.2012
Сообщений: 26,897
Записей в блоге: 1
31.01.2016, 12:31 18
Цитата Сообщение от hoggy Посмотреть сообщение
строгие гарантии, за которыми следит компилятор.
И в результате перехода с C++03 на C++11 получили бяку из-за const
В общем - я против такого.
0
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
31.01.2016, 12:49 19
Croessmah
Мне кажется, хотя я не уверен, что если указать явно на то, что объект константный, то над ним можно проводить естественные для иммутабельных объектов оптимизации.
Например, одну и туже inline функцию foo можно будет использовать как для обработки неволатильных объектов внешнего кода, так и для обработки волатильных объектов. Причём в первом случае компилятор имеет возможность "оптимизировать дорогое копирование", а во втором скопировать объект, в отличие от передачи по ссылке, гарантируя неволотильность объекта внутри foo.
0
Эксперт С++
8971 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.01.2016, 13:13 20
Цитата Сообщение от Croessmah Посмотреть сообщение
И в результате перехода с C++03 на C++11 получили бяку из-за const
ни разу ни случалась.
что впрочем и не удивительно.

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

а для случаев опустошения, которые не имеют легаси с с++03,
дизайн специально предусматривает мув-конструкторы,
и мув-операторы.
0
31.01.2016, 13:13
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
31.01.2016, 13:13
Помогаю со студенческими работами здесь

Что оптимальнее: передавать матрицу как аргумент, или же формировать её внутри функции?
Добрый вечер, уважаемые форумчане! Я столкнулась с таким вопросом в процессе оптимизации моей...

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

Передача аргументов в функцию по ссылке и указателю
Чем отличается передача по ссылке от передачи по указателю аргументов в функцию?

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru