define против глобальный const

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

02 апр 2017, 19:46

У меня тут эта мысль крутилась некоторое время.

Хочется услышать ваши мнения по этому поводу. Что где лучше и почему?
Аватара пользователя
Сионист
Сообщения: 1077
Зарегистрирован: 31 мар 2014, 06:18

02 апр 2017, 20:02

Величина, объявленная с квалификатором const, занимает память, define подставляется препроцессором. Но память расходуется и на код, причём, в случае define на каждое использование, если оно тяжеловато, например, во времена четвёртой студии лезет только в hyper, то программа при частом использовании значения раздувается, а взять по адресу - только прочитать одну и ту же память. Так что если считаете каждый байт, то зависит от значения, если нет то всё сводится к тому, что define одного и того же макроса можно применять многократно с разными значениями, а const типизирован, что полезно при его использовании в качестве фактического операнда перегруженного оператора или фактического параметра перегруженной функции.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

02 апр 2017, 20:32

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

Мой ответ следующий.
#define просто морально устарел. Это наследие С, от которого нужно избавляться. Единственное применение, которое мне известно, когда он всё ещё полезен, это макросы, прячущие в себя кусочки кода, в которых части будет заменяться, благодаря параметрам и оператору склеивания. Этот подход используется для "умной" кодогенерации. Во всех же остальных случаях от #define нужно уходить, так что если под ним константный литерал - то выбор однозначно в пользу const. Иногда, правда, будут удобны ещё и безымянные enum, но это частные случаи.

В чём же, собственно, преимущество const? Навскидку приведу несколько:
- Работает область видимости. В разных namespace можно сделать константы с одинаковыми именами, в то время как #define, вследствие того, что является просто подставляемым значением времени препроцессинга, прозрачен для пространств имен.
- Константа типизирована, так что не возникнет проблем с неявными вызовами перегруженных методов либо операторов приведения типа.
- Возможность получения адреса константной памяти, что для define невозможно, так как литерал, который скрывается под define, является r-value значением.
- Возможность положиться на компилятор в правильности оптимизации. С define оптимизации нет вообще.
- Если пойти дальше, и перейти от const к constexpr, то это шаг к метапрограммированию, что для #define вообще абсурд... но это уже 11 стандарт.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

02 апр 2017, 21:30

А разве типизация всегда хорошо? Разве не может быть случая, когда define за счет этого выигрывает определяя два неприводимых типа? С константами ведь такое не пройдет однозначно. Примера я придумать не могу, но ситуация кажется вполне реальной. Как вы думаете?
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

02 апр 2017, 22:54

Да, типизация это всегда хорошо. Хотя бы потому, что С++ - это язык со строгой типизацией. Если будет пример, который покажет, что типизация - это плохо, или хотя бы просто менее удобно, чем отсутствие типа, я с удовольствием его обсужу. Кстати, если уж на то пошло, то любой литерал в С++ тоже имеет тип, просто этот тип неявен, так что речь идёт именно о наличии явности в случае const, а не об отсутствии типа в случае #define.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1077
Зарегистрирован: 31 мар 2014, 06:18

03 апр 2017, 15:11

Romeo писал(а):Кстати, если уж на то пошло, то любой литерал в С++ тоже имеет тип, просто этот тип неявен, так что речь идёт именно о наличии явности в случае const, а не об отсутствии типа в случае #define.
Какой тип имеет NULL?

Код: Выделить всё

#include <iostream>
#include <windows.h>
void f(short int p)
{
 std::cout<<"short int";
}
void f(short int *p)
{
 std::cout<<"*";
}

void f(int p)
{
 std::cout<<"int";
}
void f(long int p)
{
 std::cout<<"long int";
}
int main()
{
 f(NULL);
 return 0;
}
что выведет?

Код: Выделить всё

#include <iostream>
#include <windows.h>
void f(short int p)
{
 std::cout<<"short int";
}
void f(short int *p)
{
 std::cout<<"*";
}

void f(int p)
{
 std::cout<<"int";
}
void f(long int p)
{
 std::cout<<"long int";
}
int main()
{
 f(nullptr);
 return 0;
}
выводит звёздочку. NULL декларирован так:

Код: Выделить всё

#define NULL 0
.
Skwoogey писал(а):А разве типизация всегда хорошо? Разве не может быть случая, когда define за счет этого выигрывает определяя два неприводимых типа? С константами ведь такое не пройдет однозначно. Примера я придумать не могу, но ситуация кажется вполне реальной. Как вы думаете?
Как раз эта ситуация не реальна. И дефайн типы не определяет. Тем более два за раз.
Romeo писал(а):Да, типизация это всегда хорошо. Хотя бы потому, что С++ - это язык со строгой типизацией.
Вовсе не поэтому. Бейсик - язык с напрочь безолаберной типизацией. Но по этой причине не типизация - плохо, а бейсик плох. Не запрягайте телегу в коня.
Romeo писал(а):Сионист, много сумбура, но большая часть верна. Только по поводу "раздувания" программы глупость. Компилятор тоже умеет оптимизировать.
Оптимизировать? Или сочинять?
Romeo писал(а):Иногда, правда, будут удобны ещё и безымянные enum, но это частные случаи.
А что это за "звери" и с чем их "едят"? Зачем вообще может понадобиться безымянный тип? Всё равно ведь нужны переменные или хотя бы параметры/операнды этих типов. А если тип безымянен, то как их декларировать?

Код: Выделить всё

enum {SW_SHOW, SW_HIDE, SW_MINIZE}
void WINAPI ShowWindow(_In_ HWND hWnd, _In_ /*Блин, что же здесь написать?*/  nCmdShow);
Дефайн то заменить не сложно. Но этот дефайн с чем то сравнивался и чему то присваивался. Как теперь объявить эти величины?
Romeo писал(а):- Возможность положиться на компилятор в правильности оптимизации. С define оптимизации нет вообще.
Кто то только что утверждал обратное.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

03 апр 2017, 18:17

Сионист писал(а): Какой тип имеет NULL?
Как раз эта ситуация не реальна. И дефайн типы не определяет. Тем более два за раз.
Ещё раз для тех, кто программируя двадцать лет, до сих пор не удосужился прочесть стандарт. Каждое выражение в С++ имеет свой тип, поэтому язык называется языком со строгой типизацией. Это касается и летералов. Любой целочисленный литерал имеет тип int, если дополнительно не указан суффикс. Для литерала 0 сделано исключение в правилах приведения именно потому, что NULL определен, как 0.
Сионист писал(а): Вовсе не поэтому. Бейсик - язык с напрочь безолаберной типизацией. Но по этой причине не типизация - плохо, а бейсик плох. Не запрягайте телегу в коня.
Неверное высказывание. Любой язык хорош для своей цели. И да, отсутствие типизации в языке с нестрогой типизацией, например в JS, будет плюсом.
Сионист писал(а): Оптимизировать? Или сочинять?
Уточни, что ты имеешь в виду под словом сочинять. Мне не знаком этот термин в применении к компиляторам.
Сионист писал(а): Блин, что же здесь написать?
int
Сионист писал(а): Кто то только что утверждал обратное.
Либо ты меня не читаешь, либо читаешь, но не понимаешь. Укажи, где я утверждал обратное.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1077
Зарегистрирован: 31 мар 2014, 06:18

03 апр 2017, 18:20

Romeo писал(а):Либо ты меня не читаешь, либо читаешь, но не понимаешь. Укажи, где я утверждал обратное.
Вот же:
Сионист, много сумбура, но большая часть верна. Только по поводу "раздувания" программы глупость. Компилятор тоже умеет оптимизировать.
Или не читаешь именно ты.
Romeo писал(а):int
Нет. Надо указать имя того самого enum. А его нет.
Romeo писал(а):Неверное высказывание. Любой язык хорош для своей цели.
Чтоб изучить азы и сразу перейти к чему то посерьёзней?
Romeo писал(а):И да, отсутствие типизации в языке с нестрогой типизацией, например в JS, будет плюсом.
Попробуйте привести хоть один подтверждающий пример.
Romeo писал(а):Уточни, что ты имеешь в виду под словом сочинять. Мне не знаком этот термин в применении к компиляторам.
Это не термин. И преподавателем русского языка я не нанимался.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

03 апр 2017, 18:40

Сионист, с тобой невозможно вести адекватный диалог. То количество глупостей, которые ты вываливаешь, просто обезоруживает. Если пытаться уличить тебя в каждой, то ты начинаешь бросаться какашками. Если пытаться отвечать по верхам, чтобы не закопаться в этом всем с головой, то ты начинаешь придираться.

Пожалуй, я просто воспользуюсь советом, который когда-то дал Марк Твен. "Никогда не спорьте с дураками. Вам придётся опуститься на их уровень, а там они задавят вас своим опытом".

Дискуссия окончена.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1077
Зарегистрирован: 31 мар 2014, 06:18

03 апр 2017, 18:54

Хоть одну назови. В оличие от. Я написал, что частое обращение к задефайненной тяжёлой величине раздувает программу. Ты на это пишешь, что нет, потому что компилятор умеет оптимизировать и в том же посте пишешь, что дефайн не оптимизируется. Вот тебе первая глупость. Зачем то придумал термин "сочинять" и просишь его пояснить. Вот тебе вторая. Не можешь определиться, является ли плюсом языка типизация, или её отсутствие. Это уже третья. Избавляешься от дефайна не потому что у него полно недостатков, а потому что он давно известен. Это четвёртая. Ну избавляйся тогда и от for, while, do while, if, if ellse, switch case, return, int, float. Это ведь тоже наследие c, а for - даже фортрана.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Ответить