const в аргументах методов
От: yaser Украина  
Дата: 03.04.16 06:11
Оценка:
Добрый день.

Есть класс
class Drink {
private:
   std::string m_name;
public:
  std::string value(const std::string company, const int) const;
  const std::string& name() const;
   
}

Собственно 2 вопроса
1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?
2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?
Отредактировано 04.04.2016 12:19 Кодт . Предыдущая версия .
Re: const в аргументах методов
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 03.04.16 06:57
Оценка: +2 -3
Здравствуйте, yaser, Вы писали:

Y>Собственно 2 вопроса

Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?

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

Y>2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?


Если такая ситуация возможна, то плохо, если нет, то нет.
Ce n'est que pour vous dire ce que je vous dis.
Re: const в аргументах методов
От: Zhendos  
Дата: 03.04.16 11:54
Оценка: +1 -1
Здравствуйте, yaser, Вы писали:

Y>Добрый день.


Y>Есть класс


Y>class Drink {

Y>private:
Y> std::string m_name;
Y>public:
Y> std::string value(const std::string company, const int) const;
Y> const std::string& name() const;

Y>}


Y>Собственно 2 вопроса

Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?

Когда банально хочется быть уверенным что внутри функции параметр случайно не меняется.
Например, `double f(const double coef)`, если внутри функции решается какое-то уравнение с коэффициентами
и там есть вычисляемые переменные типа `coef2`, а придумать им более различимые имена напряжно,
то `const` переложит проверку на плечи компилятору.

Y>2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?


rust поможет переложить проверку на подобную ситацию на плечи компилятора, а в c++ либо скорость и самоконтроль, или копирование.
И в c++ std::string не может быть reference-counting поэтому по любому будет лишнее выделение памяти,
если строка большая.
Re: const в аргументах методов
От: Vamp Россия  
Дата: 03.04.16 14:27
Оценка:
Здравствуйте, yaser, Вы писали:


Y>Собственно 2 вопроса

Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?
Мне трудно представить себе ситуацию когда передача std::string по константному значению может быть оправдана. Если аргумент не меняется, то почему бы не передать его по константной ссылке и избежать возможного лишнего копирования?
Y>2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?
Это зависит от контракта. Автор класса определяет контракт и устанавливает границы. Если контракт твоего класса подразумевает, что возвращаемое значение не может пережить сам объект (см. std::string::c_str), то все ОК.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: const в аргументах методов
От: Vamp Россия  
Дата: 03.04.16 14:31
Оценка:
DR>Константность значения параметра не входит в сигнатуру метода,так что смысла в этом столько же, сколько в константности локальных переменных метода.

DR>Если такая ситуация возможна, то плохо, если нет, то нет.


Это не ответ на вопрос.
Да здравствует мыло душистое и веревка пушистая.
Re: const в аргументах методов
От: Alexander G Украина  
Дата: 03.04.16 15:47
Оценка:
Здравствуйте, yaser, Вы писали:

Y>Собственно 2 вопроса

Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?

Именно, нет смысла.
И ещё есть тонкость, что параметр типа std::string действительно константный, а параметр типа int может быть не-константным в другом объявлении.
В общем, лучше не надо.

Y>2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?


Ещё может быть такое, что значение, переданное по ссылке, поменялось внутри класса.
Так, для многопоточного использования в случае возврата по значению достаточно защитить все потенциально-многопоточные обращения к m_name мьютексом, при возврате по сслыке потокобезопасность добавить куда сложнее.
Русский военный корабль идёт ко дну!
Re: const в аргументах методов
От: tstalker Украина  
Дата: 04.04.16 06:32
Оценка:
Здравствуйте, yaser, Вы писали:

Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?


Я обычно следую простым правилам:
1. Если аргумент внутри функции не модифицируется — пишу const.
2. Если аргумент типа класса — передаю по ссылке.
3. Если аргумент указатель и исходный объект не модифицируется — пишу const.
4. Если аргумент массив и исходные данные не модифицируются — пишу const указатель.

Y>2. Насколько хорошо возвращать ссылку на члены класса?


Возврат нестатическим методом класса ссылки на член класса — это норма. (Ц) Малышева .
В особенности если ссылка константная.
Бойся возврата указателя либо ссылки на локальный объект функции!
Вот там действительно подводные камни.
К счастью, обычно компилятор предупреждает об этом.

Y>Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?


Видимо, ты хотел сказать нет объекта класса?
Don't worry, be happy! (C) Bob Marley
Если нестатический метод класса вызывается от имени объекта класса, можно не переживать.
Вот если от имени указателя на несуществующий объект класса — тогда да, проблема.
Re[2]: const в аргументах методов
От: yaser Украина  
Дата: 04.04.16 08:10
Оценка:
1. По поводу передачи параметров с модификатором const по значению понял. +/- так думал, но хотел убедится в своих знаниях. Понятно что когда передаешь параметр по ссылке, то const имееть ОГРОМНОЕ значение.
2. Есть большой отдел разработчиков. Вы проектируете класс, не понятно кто, как, когда будет им пользоваться. Понятно, что если метод private, то для оптимизации взаимодействия внутренних метода класса вполне приемлимо возврат по const object_ref, но если метод паблик — не понятно как разработчик воспользуется возможностями. Может не стоит проектировать класс (в общем случае) публичные методы которого возвращают const object_ref?
Re[3]: const в аргументах методов
От: tstalker Украина  
Дата: 04.04.16 08:36
Оценка:
Здравствуйте, yaser, Вы писали:

Y>2. Есть большой отдел разработчиков. Вы проектируете класс, не понятно кто, как, когда будет им пользоваться. Понятно, что если метод private, то для оптимизации взаимодействия внутренних метода класса вполне приемлимо возврат по const object_ref, но если метод паблик — не понятно как разработчик воспользуется возможностями. Может не стоит проектировать класс (в общем случае) публичные методы которого возвращают const object_ref?


Бро, я же писал тебе выше: это норма.
Ничего здесь опасного нет.
Вот навскидку простенький пример:
#include <string>
#include <iostream>

class C
{
public:
    C(const std::string& s): s(s)
    {}

    C(const C& c): C(c.s)
    {}

    std::string& get(void)
    {
        return s;
    }

    const std::string& get(void) const
    {
        return s;
    }

private:
    std::string s;
};

int main(void)
{
    C x("aaaaa");
    std::cout << x.get() << std::endl; // std::string& C::get(void)
    const C y(x);
    std::cout << y.get() << std::endl; // const std::string& C::get(void) const
    x.get() = "bbbbb"; // std::string& C::get(void)
    const C& z(x);
    std::cout << z.get() << std::endl; // const std::string& C::get(void) const
}

В комментариях специально поставил пояснения, какие именно методы get() вызываются.
Так что смело возвращай ссылки на члены класса и пой:
Don't worry! Be happy!
Re[2]: const в аргументах методов
От: LaptevVV Россия  
Дата: 04.04.16 09:36
Оценка:
Z>Когда банально хочется быть уверенным что внутри функции параметр случайно не меняется.
Z>Например, `double f(const double coef)`, если внутри функции решается какое-то уравнение с коэффициентами
Z>и там есть вычисляемые переменные типа `coef2`, а придумать им более различимые имена напряжно,
Z>то `const` переложит проверку на плечи компилятору.
Нет смысла в этом случае передавать по значению.
Вполне по константной ссылке делает то же самое — запрещает изменять параметр внутри.
Не только посредством присваивания, но и посредством ввода извне.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: const в аргументах методов
От: dead0k  
Дата: 04.04.16 10:50
Оценка:
Здравствуйте, tstalker, Вы писали:

T>Бро, я же писал тебе выше: это норма.

T>Ничего здесь опасного нет.
T>Вот навскидку простенький пример:

BoxOfTNT * box = new BoxOfTNT();
TNT & stick (box_of_TNT->choose_one_stick_of_TNT());
delete box;
stick.prepare_to_use(); // <- BOOM

Оно, конечно, сам-себе буратино, но факт остается фактом — возвращать по значению — безопасней.
ps/
И да, указатель не является необходимым условием. Можено передать ссылку на шашку в конструктор другого класса, экземпляр которого будет возвращен из функции по значению, при этом, естествено, ящик и шашка, на которую есть ссылка, будут разрушены по выходу из этой функции.
Отредактировано 04.04.2016 10:56 dead0k . Предыдущая версия . Еще …
Отредактировано 04.04.2016 10:55 dead0k . Предыдущая версия .
Отредактировано 04.04.2016 10:53 dead0k . Предыдущая версия .
Re[3]: const в аргументах методов
От: watchmaker  
Дата: 04.04.16 11:12
Оценка: 3 (2) +2
Здравствуйте, LaptevVV, Вы писали:

Z>>Когда банально хочется быть уверенным что внутри функции параметр случайно не меняется.

Z>>Например, `double f(const double coef)`, если внутри функции решается какое-то уравнение с коэффициентами
Z>>и там есть вычисляемые переменные типа `coef2`, а придумать им более различимые имена напряжно,
Z>>то `const` переложит проверку на плечи компилятору.
LVV>Нет смысла в этом случае передавать по значению.
LVV>Вполне по константной ссылке делает то же самое — запрещает изменять параметр внутри.

Не совсем. Есть ещё важное отличие — код без ссылки может работать быстрее. Выше приведён пример с решением уравнения, я же приведу пример ещё проще: умножение вектора на число:
void mul_const_ref(float a[], size_t n, const float& factor) {
  for (size_t i = 0; i < n * 4; ++i)
    a[i] *= factor;
}

void mul_const_value(float a[], size_t n, const float factor) {
  for (size_t i = 0; i < n * 4; ++i)
    a[i] *= factor;
}
Такой код обычен и должен отлично векторизоваться даже не очень современными версиями компиляторов. В нём только n * 4 добавлено для удобства, чтобы не загромождать рассмотрение случаями, когда почти весть массив обрабатывается векторно, но остаток — скалярно.
Смотрим на результат: https://godbolt.org/g/1No0ev

Функция mul_const_value использует инструкции векторного умножения — тут всё более-менее хорошо.
Функция mul_const_ref же не только не векторизовалась, но и делает нечто странное — на каждой из итераций загружает factor из памяти заново!
В общем, даже с простой задачей умножения вектора на константу вышло фиаско — передача аргумента по константной ссылке всё портит.

Почему так происходит? Потому что в С++ нет ключевого слова restrict или аналога для ссылок и указателей. То есть компилятор не может гарантировать, что на очередной итерации присваивание a[i] не изменит значение factor. Поэтому он и вынужден на каждой итерации перечитывать это значение из памяти — а вдруг оно изменилось. Ведь менять значение объекта, на которое указывает константная ссылка, не запрещено в стандарте.

Впрочем, некоторые компиляторы вставляют в начало функции несколько проверок на то, что диапазон памяти, занимаемый массивом a[0:n*4], не пересекается с памятью, занимаемой factor. И в зависимости от результата переходят на векторную или на скалярную версию. Так не теряется возможность векторизовать цикл, но из-за дополнительных проверок и из-за дополнительного кода, такие функции получаются большими по размеру, а работают всё равно чуть медленнее, чем если бы мы сразу передали factor по значению.
Re[4]: const в аргументах методов
От: yaser Украина  
Дата: 04.04.16 12:29
Оценка:
Здравствуйте, tstalker, Вы писали:

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


Y>>2. Есть большой отдел разработчиков. Вы проектируете класс, не понятно кто, как, когда будет им пользоваться. Понятно, что если метод private, то для оптимизации взаимодействия внутренних метода класса вполне приемлимо возврат по const object_ref, но если метод паблик — не понятно как разработчик воспользуется возможностями. Может не стоит проектировать класс (в общем случае) публичные методы которого возвращают const object_ref?


T>Бро, я же писал тебе выше: это норма.

T>Ничего здесь опасного нет.
T>Вот навскидку простенький пример:
T>
T>#include <string>
T>#include <iostream>

T>class C
T>{
T>public:
T>    C(const std::string& s): s(s)
T>    {}

T>    C(const C& c): C(c.s)
T>    {}

T>    std::string& get(void)
T>    {
T>        return s;
T>    }

T>    const std::string& get(void) const
T>    {
T>        return s;
T>    }

T>private:
T>    std::string s;
T>};

T>int main(void)
T>{
T>    C x("aaaaa");
T>    std::cout << x.get() << std::endl; // std::string& C::get(void)
T>    const C y(x);
T>    std::cout << y.get() << std::endl; // const std::string& C::get(void) const
T>    x.get() = "bbbbb"; // std::string& C::get(void)
T>    const C& z(x);
T>    std::cout << z.get() << std::endl; // const std::string& C::get(void) const
T>}
T>

T>В комментариях специально поставил пояснения, какие именно методы get() вызываются.
T>Так что смело возвращай ссылки на члены класса и пой:
А если так:
int main(void)
{
    C* very_good_style_obj = new x("aaaaa");
        const std::string& str = very_good_style_obj->get();
        delete very_good_style_obj;
    std::cout << str << std::endl; // std::string& C::get(void)
         
}
Re[5]: const в аргументах методов
От: tstalker Украина  
Дата: 04.04.16 14:27
Оценка:
Здравствуйте, yaser, Вы писали:

Y>А если так:

Y>
Y>int main(void)
Y>{
Y>    C* very_good_style_obj = new x("aaaaa");
Y>        const std::string& str = very_good_style_obj->get();
Y>        delete very_good_style_obj;
Y>    std::cout << str << std::endl; // std::string& C::get(void)
Y>}
Y>


Ну это уже откровенное жульничество.
Так пишут только индусы.
Защитить данные от подобного варварства помогут умные указатели:
int main(void)
{
    std::unique_ptr<C> p(new C("abcde"));
    const std::string& s(p->get());
    std::cout << s << std::endl;
}
Re[6]: const в аргументах методов
От: dead0k  
Дата: 04.04.16 14:46
Оценка:
Здравствуйте, tstalker, Вы писали:

T>Защитить данные от подобного варварства помогут умные указатели:

int main(void)
{
    std::unique_ptr<C> p(new C("abcde"));
    const std::string& s(p->get());
    p.reset(new C("fghij")); // пой вместе со мной, сестра, и танцуй, ведь это индийское кино
    std::cout << s << std::endl;
}
Re[7]: const в аргументах методов
От: tstalker Украина  
Дата: 04.04.16 16:38
Оценка:
Здравствуйте, dead0k, Вы писали:

D>
D>int main(void)
D>{
D>    std::unique_ptr<C> p(new C("abcde"));
D>    const std::string& s(p->get());
D>    p.reset(new C("fghij")); // пой вместе со мной, сестра, и танцуй, ведь это индийское кино
D>    std::cout << s << std::endl;
D>}
D>


Наш ответ дедушке:
int main(void)
{
    std::unique_ptr<C> p(new C("abcde"));
    std::unique_ptr<std::string> s(new std::string(p->get()));
    p.reset(new C("fghij"));
    std::cout << *s << std::endl;
    *s = p->get();
    std::cout << *s << std::endl;
}

А если серьёзно, то таки да — встроенные ссылки и указатели запросто могут потерять актуальность.
Кроме того, механизм встроенных ссылок и указателей слабо взаимодействует с умными указателями и не синхронизируется автоматически.
А потому — внимательность, внимательность и ещё раз внимательность.
Re: const в аргументах методов
От: __kot2  
Дата: 04.04.16 17:58
Оценка:
Здравствуйте, yaser, Вы писали:
Y>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?
а в чем смысл передачи по значению тут? надо по const &. это, конечно, про string. const int никогда не встречал. не, вру, однажды — знакомый прочитал книгу GPU gems, что, мол, надо везде передавать по const & и стал везде писать const int &x.

единственная причина писать параметр тут const int — если есть член класса с таким же именем и не хочется перепутать внутри метода при записи значения. но это не совсем нормальный подход.

Y>2. Насколько хорошо возвращать ссылку на члены класса? Может быть история что ссылка осталась, а класса нет. Может лучше отдавать по значению?

обычно по значению отдают. бывает, что есть метод типа const &data() const который возвращает ссылку на внутренний буфер, если нужно по какой-то причине. в остальных случаях лучше по значению
Re[5]: const в аргументах методов
От: Erop Россия  
Дата: 04.04.16 20:20
Оценка:
Здравствуйте, dead0k, Вы писали:

D>
D>BoxOfTNT * box = new BoxOfTNT();
D>TNT & stick (box_of_TNT->choose_one_stick_of_TNT());
D>delete box;
D>stick.prepare_to_use(); // <- BOOM
D>

D>Оно, конечно, сам-себе буратино, но факт остается фактом — возвращать по значению — безопасней.
D>ps/
Провал тут случился в тот момент, когда ты решил хранить ссылку, а не копию, в коде, который что-то рушит. Никто не заставлял тебя хранить ссылку, а не копию...
Когда из метода доступа возвращают ссылку, а не копию, то решение о том, что хранить отдают наружу просто.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: const в аргументах методов
От: Erop Россия  
Дата: 04.04.16 20:27
Оценка: +1
Здравствуйте, __kot2, Вы писали:

__>обычно по значению отдают. бывает, что есть метод типа const &data() const который возвращает ссылку на внутренний буфер, если нужно по какой-то причине. в остальных случаях лучше по значению


Зачем? Всё равно же решение хранить копию или ссылку принимают снаружи?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: const в аргументах методов
От: B0FEE664  
Дата: 05.04.16 09:06
Оценка: +1
Здравствуйте, __kot2, Вы писали:

Y>>1. Насколько оправдано написание const спецификатора при передаче в метод параметров по значению? Может в этом нет смысла, ведь идет копирование?

__>а в чем смысл передачи по значению тут? надо по const &. это, конечно, про string.

Согласно "последнему постановлению ВЦСПС" std::string надо передавать по значению (и без const) в том случае, если внутри функции эту строку подлежит сохранить в другую переменную, например, в член класса:

class Drink
{
  public:
    void SetName(std::string strName)
    {
      m_name = std::move(strName);
    } 
  private:
     std::string m_name;
};
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.