Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

const-correctness in C++ code

Доброго времени суток!

У меня назрел вопрос (на сей раз уже не настолько нубский, как в моём предыдущем топике) к тем, кто пишет на C++.

Пишете ли Вы const-корректный код? Например, были бы уместны в Вашем коде следующие два квалификатора const, отмеченные (1) и (2) в примере ниже? Или же Вы предпочитаете не париться насчёт подобных вещей? Меня интересует отношение наших C+±программистов к вопросу const-корректности.

class Gadget
{
private:
    int foo_;
    // ...
public:
    int GetFoo() const/*(1)*/ { return foo_; }
    // ...
};

void SomeReadOnlyFun(const/*(2)*/ vector<Widget> & widgets)
{
    // reads the vector without modifying anything
}
👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Пишете ли Вы const-корректный код?
да, разумеется
а от треда у меня фейспалм

Ну да ставлю conts и в первом и во втором случаем, меня другое интересует.
Где то тут прочитал -

Мне интересно, Александр, Вы действительно считаете, что передавать объекты по ссылке (не константной) — это хорошая практика? Или, может быть, Вы думаете, что объекты вообще нужно по значению передавать?

Ну а если стоит такая задача —

void SomeReadOnlyFun(vector<widget> & widgets)
{
// modify incoming vector or some other object !!!
}

То что делать — задача неправильная (изменить состояние объекта передающегося по ссылке) или есть какие то паттерны как это («передача объекта по ссылке (не константной)») обойти?

Это мне все понятно.
Но откуда правило — «неконтсантных ссылок на объекты НЕ ДОЛЖНО быть», откуда ноги ростут ?

А где Вы слышали про такое правило? Глупость какая-то ведь: если мы хотим передать объект в функцию для записи (чтоб можно было менять оригинальный объект, а не его локальную копию) — передавать надо как раз таки неконстантную ссылку.
И стандартная библиотека так делает. Например: www.cplusplus.com/...string/getline

Ну так вот, прочитал —

Мне интересно, Александр, Вы действительно считаете, что передавать объекты по ссылке (не константной) — это хорошая практика? Или, может быть, Вы думаете, что объекты вообще нужно по значению передавать?
интересно стало почему же это «плохая практика»...

Думаю, автор этого комментария имел в виду «передавать объекты по ссылке (не константной) ТОЛЬКО ДЛЯ ЧТЕНИЯ».

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

100 % протупил, название ф-ции в таком случае тоже неплохо бы поменять.
Предположим так —

void changeSomethingFunc(vector<widget> & widgets)
{
// modify incoming vector or some other object !!!
}

Вот еще мнение против констодроча rsdn.ru/...pp/QnAconst.xml
И вообще автор явно выбрал примеры, на которые явно ответ однозначен, своего рода манипуляция. Речь шла о — если эт логический конст — должен ли он быт всегда констом. Это все равно что спрашивать . Стоит ли считать на калькуляторе . И пример 2+2 и 3+3

Александр, скажите, а Вы знакомы с трудами, например, Майерса? Или все вокруг профаны, один Вы могучий спец?

(1) — так, (2) — так.
А що стосується const vector<widget>& то завжди знайдеться умілець який створить локальну копію вектора де буде усе довго і нудно копіюватися, а потім руйнуватися. Тому треба передавати або константні ітератор(и), або колекцію якихось розумних вказівників, або лямбду що повертає елементи по черзі чи за індексом, або свій тип навколо колекції що не дозволяє копіювання.

всегда надо использовать const где только можно, это серьезно влияет не только на поддержку приложения в дальнейшем но и ускоряет производительность как по памяти так и по CPU (это сильное подспорье компилятору для оптимизаций)

Про поддержку — абсолютно согласен. А вот насчёт оптимизаций спорная тема. Если и помогает, то незначительно. Саттер об этом писал: www.gotw.ca/gotw/081.htm

Ну это само собой :)

Якщо restrict допомагає "досягнути програмам на Сі швидкість програмам на Фортрані, то const тим паче. Особливо, якщо працюєш з вказівниками.

Дядя Кармак завещал везде писать const. Я как узнал сразу начал так делать, на практике осознал что это удобно. Целишься в ногу, а тут опа и конст. Очень удобно.

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

Я даже его быстрый квадратный корень использовал когда-то, но то больше для смеху было.
А так нормальный код, DOOM3 почитайте, там все понятно.

Пишете ли Вы const-корректный код?
Стараюсь, по мере возможностей, очень хорошо увеличивает, этот... как его... intention.

С const-correctness можно копнуть глубже:
1). Type* getType() const; //все ок с точки зрения компилятора — бинарная константность соблюдена
2). const Type* getType() const; //все ок с точки зрения логики — логическая константность соблюдена

1 вариант некорректен, так как сильно вводит в заблуждение, сталкивался с таким лично: часто Type* может быть композицей вышестоящего класса, и возвращение неконстантного указателя/ссылки из константного метода приводит к трудно-улавливаемым багам. Например, когда в функцию передается константный объект (такое при просмотре кода берется во внимание при поске бага: «ага, объект передается константный, значит ничего не меняется, не буду смотреть внутрь, иду дальше»), а тот меняет что-то у части класса через константный метод.

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

Не уверен, что до конца Вас понял, но вообще, насколько мне известно, в подобных случаях принято делать две перегруженные версии подобного геттера:
1) Type* getType();
2) const Type* getType() const;
Чуть больше писанины, но проблема согласованности константности объекта с константностью того, на что он ссылается, полностью решается.

Так, константні методи, як було зазначено, спрощують читання коду. Коли дивишся інтерфейс без реалізації, наявність константних методів значно спрощує.
Константні параметри також хороша штука, по-перше спрощують читання, по-друге «захист від дурня» аби ти ненароком не змінив в тілі функції параметр.

«mutable», «const_cast», other дуже обережна вокористовувати, як правило, коли в коді більше одного разу щось таке трапляється — велика вірогідність, що код задизайнений не зовсім правильно.

Абсолютно згоден з Вами.
Про mutable лише додам, що даний специфікатор цілком нормально використовувати, коли логічна і фізична константність об’єкта відрізняються. Наприклад, при реалізації кешування, лінивих обчислень тощо. Але, звісно, таке в продакшні навряд чи буде часто зустрічатися.

Ну насчет продакшена не до конца согласен. mutable идет полным ходом для использование мьютексов внутри константных методов. Обычная практика.

Ну ту просто великие теоретики . Позуем много поточность — конечно пользуем. Блюдем конст — блюдем. О мютебл это плохо. Только как они получают конст без мютебла и глобал глобал локов ? :) Кстати реальная тема как распознать балабола.

Т.е. Вы, как великий практик считаете, что нет смысла ставить const на метод, который таки не изменяет состояние объекта, но при этом требует захват мьютекса? И как Вы смотрите на то, что в Ваш класс закрадется другой специалист из Самсунга и засунет полный ахтунг в какой-нибудь геттер (утрирую конечно)?

а конст от этого защитит ? опять же мутабле ни кто не отменял. ну и каст. Ладно , надо поработать. Вечером еще можно потроллить :)

Ну опять таки, в крестах выстрелить себе в ногу до конца запретить никому нельзя. Но есть шанс, что когда компилятор ругнется, разработчик не пойдет ставить mutable на все подряд, а задумается нахрена же там стоит const. Точно так же можно начать холивар «а нужно ли использовать override из нового стандарта». Это просто может («может» — здесь ключевое слово) помочь избежать ошибок.

Как по мне, то это еще и значительно увеличивает надёжность кода.

Ссылку на что? На опыт?

Хотите ссылку — вот Вам ссылка:
Книга Скотта Мэйерса «Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ», правило № 3.

и где там написано что надо констные методы хренячить везде т..к это избавит вас от ошибок ?

Вы вообще о чем ? :) Причем тут код, компиляторы к константрой дрочи ? Был гет что-то там не констный. .он не где не вызывается в констном контексте. Это не либа , и некто кроме тебя и коллег пользоваться не будет. как улучшится надежность если добавить конст ?

Ну в общем-то все тут ясно.

Это не либа
А если либа? :) Там вот эта Ваша «дрочь» оправдана? Свидетель путается в показаниях.
и некто кроме тебя и коллег пользоваться не будет. как улучшится надежность если добавить конст
А завтра будут те же коллеги? А послезавтра?

Это пустой спор, Александр. Вы не участвуете в дискуссии, Вы прибегаете к явной, вызывающей провокации. Что там говорили про спецов из Самсунга...?

Мне интересно, Александр, Вы действительно считаете, что передавать объекты по ссылке (не константной) — это хорошая практика? Или, может быть, Вы думаете, что объекты вообще нужно по значению передавать?

Причем тут константная ссылка ? Нужно что-то сделать по константной ссылке и вызвать метод. Можно сделать константный метод. Но я не вижу смысла для всех гетеров деалть константность, где надо делать что-то больше чем просто написать конст.

А при том, что у объекта, который передан по константной ссылке, можно вызывать только const-методы. Поправьте меня, если я ошибаюсь.

но вы же не все методы вызываете . ведь правда.

Идите работать, распознаватель речевых образов вы наш :) Кстати, где ваша распознавалка используется ? :)

Открыл по ссылке — все с вами ясно

Открыл по ссылке — все с вами ясно

И что вам ясно, сахарок?

Виктор, самописный синтез? У вас фазы что-то не совпадают. Булькает немножко.

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

Я не совсем понимаю только, зачем солу использовали, если мат аппарат фазового вокодоера уже и в те времена был доступен. Не просветите? Или сделали то, что быстрее, а потом уже решили дописывать.

А как вы интонации делали, если не секрет? Вот это дял меня тайна за семью печатями. Какая-то база интонационная примеров? Или мат аппарат построеннный на лингвистике и правилах речи?

Офигеть!
Знать бы тогда, что делать надо для англоязычного рынка, сейчас бы на островах яхтами мерялись с Элисоном.
И сейчас не слышал ни одного генератора, который бы так хорошо интонации и паузы расставлял.
.
Может еще не все потеряно? Потребность ведь все еще большая в мире.

Відповідь від нуба. Звісно доцільно. Особисто для мене це як мінімум спрощує читання, адже якщо щось змінюватися не повинно доцільно на це вказати явно.

«Надо, Тарас! Надо ... » :)

Я на Сі навіть restrict використовую.

Нет, вопрос из 2015. Именно в 2015 году один уважаемый сеньор из Самсунга тут на DOU мне сказал, что «const-корректный дроч в реале актуален только для написания библиотек». Вот я и решил спросить мнение у других людей, что они думают по этому поводу.

Минусы в том что , в большинстве случаев из-за элементов синхронизации и прочего константнасть только логическая. Нафига делать константным то что ни кому в константном виде не надо. Кому понадобилось тот добавил. Я не говорю про поля которые возвращаются просто гетером.

Аааа, так это Вы тот

один уважаемый сеньор из Самсунга

Вы не давайте больше советов, пожалуйста. Не надо.

из-за элементов синхронизации и прочего константнасть только логическая
Так что мешает только те самые элементы синхронизации сделать mutable, чтобы их можно было изменять в const методах, в то время как остальные члены класса будут защищены от несанкционированной модификации? Mutable для этого ведь и придумали: чтоб позволить менять физическую константность объекта там, где не нарушается логическая.
Делать всякие мьютексы и прочее mutable — обычная практика.

Кстати, многие здесь упоминали труды Мейерса. Так вот, он в своей новой книге «Effective Modern C++» как раз об этом также писал (Item 16: «Make const member functions thread safe»).

Что тут скажешь, киевский самсунг никогда не отличался качеством кадров. При всем уважении.

а как там платят?

Ну так если нормально платят — значит всех устраивает, это же хорошо)

Это станет исключительно их проблемой, когда самсунг свой офис здесь закроет, а они попробуют найти другую работу. Нет ничего хуже плохого(или никакого) опята на теплом месте.

Вам конечно из Минска виднее. Видать каждый за честь имеет приехать к вам и пройти собеседования :)

Гы. какой неугомонный. Вы какой-то озабоченный.

Не холивара ради. Самсунг компания большая. Делаю вывод по тем, с кем имел честь общаться :) Но в целом, статистика неутешительная.

правило простое — либо const по всему проекту и никаких const_cast, либо в нем нет смысла.

Гото пользуется много где. Например в Linux kernel. В гугл тестах часто пользуется. Скажу сразу, чтоб небыло летящих говн — я его не пользую.

Кернел еще с утра был как бы не на плюсах написан, нет?

А что в чистых сях goto использовать кошерно?

Иногда да. Где рулит исключительно производительность.

Та я в принципе не против, в ffplay.c в последний раз встречал. Но все равно считаю, что нужно воздерживаться

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

Чаще всего все же в критических по производительности секциях, где нет уверенности в том, что компилятор вытянет call внутри цикла в inline и не сбросит конвеер. Что довольно актуально в портабельных проектах, как сам линукс, ffmpeg etc.
По моим наблюдениям.
.
Но в ffplay, насколько помнится, оно изображает try-except блок и да, вполне компактно и осмысленно в том случае.

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

Обычно вариации на тему try-except. Бывает иногда goto retry, если явный цикл получается очень корявым.

класно передьоргуєш.
хтось казав про ядро на хрестах?

Нифига. С и С++ два разных языка. Так что передернули до меня.

пан — блондинко?
чим гото в сях відрізняється гото в хрестах?
параметрами, сигнатурою, об"єктно-орієнтованістю..?

Те, що в С звичайно робиться через goto, в C++ має бути або автоматичною деструкцією об’єкта, або виключенням. Десь так.

Ну і досить різний стиль типового коду там і там.

linux/Documentation/CodingStyle:
paste.ee/p/DHI38

C++, грубий переклад:
paste.ee/p/C7MyI

Звісно таке відношення до пам’яті в ядрі не канає, тому ядра зазвичай не пишуть на C++.

Тобто? В CodingStyle то приклад правильного використання goto
www.kernel.org/...ion/CodingStyle Chapter 7.

The goto statement comes in handy when a function exits from multiple
locations and some common work such as cleanup has to be done. If there is no
cleanup needed then just return directly.
==
це і їжу понятно, от мене цікавить чим С++, для контролю виконання “гото” буде відрізнятися від пуреС?

ще про «пімпл» забув і про RTII

ну да, я теж много умних слов знаю

Это всё замечательно до тех пор, пока не используются объекты ОС, которых нет в обвёртке от std.

Это как раз тот пример, когда время тратится на красоту вместо функциональности.

Нафига эти придирки?
Ясно, что результирующий jmp будет такой же, но в плюсах оно крайне противопоказано по известным причинам, а в С — как правило не более чем признак смуглого кода.
.
ЗЫ. А ECU/EEC на плюсах бывают?

я нуб в хрестах,
по яким таким

известным причинам
?

ECU/EEC
а це що фігня?

да куда пуре Сникам, ми ж авно руками кидаєм,
а хрестах там все культурно, лопатою

краще все ж в Java, сидиш в ескаваторі в костюмчику, в туфлях а не кирзачах і ватніку

ладно,
я чекаю нового вброса
від п.Taras Morozovsky
цікаво чим він ще озабочений

Чим завгодно, лиш би всякі сеньйори побугуртили :)

Я не можу це сказати про себе. Є у простоті Сі своя чарівність. У С++ як почнеш використовувати усі його можливості, потім вже воюєш не з проблемами, а з самим С++. Інколи підробляєш компілятором, щоб дослідити, що там з твоїм кодом усередині трапляється.

Так що на роботі С++, вдома для душі — Сі.

В плюсах куча автоматизации. Начиная с тех же деструкторов. И выпрыгивание из внутренней логики по goto ее в большинстве случаев тупо сломает.
Ну и Страуструп в свое время придумывал средства плюсам именно для того, чтобы от goto окончательно избавиться. Те же try-catch блоки (больше мое имхо, т.к. прямо об этом он не писал нигде).

ECU/EEC
а це що фігня?
Сорри, перепутал
homeauto
с
Automotive

Конечно. Все так делают не парься. Если сильно надо всегда этот const можно убрать

Если он написан по уму и надо убрать — значит возможно что-то пошло не так.

Підписатись на коментарі