Re[17]: const char* const - Путаница
От: Николай Ивченков  
Дата: 20.12.09 00:09
Оценка: 13 (2)
Юрий Жмеренецкий:

ЮЖ>>>Под 'argument passing' понимается не 'expression passing', а инициализация (8.5.3/2). Если initializer expression является rvalue, то объект (параметр) будет инициализирован его значением (8.5/14, возможно косвенно в некоторых случаях). Вот это я имел ввиду (хотя там формулировка не совсем удачная).


НИ>>Как это влияет на вывод шаблонных аргументов?

ЮЖ>Здесь — никак, я уже сказал об этом.

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

НИ>>В нашем случае P — это T &


ЮЖ>Это неверно.


Если P — это не T &, то что тогда? И заодно хотелось бы увидеть примеры, когда P представляет собой "reference type" или "cv-qualified type", а также когда P записан в виде template-id (в стандарте есть фраза "If P is a class, and P has the form template-id, then [...]").

ЮЖ>Из этого определения следует, что появлению template parametr'a должна предшествовать такая конструкция: 'template <'.


Формулировка "function template parameter type (call it P)", на мой взгляд, выбрана неудачно, но P — это определённо не template parameter и не type of template parameter (в обоих случаях дальше по тексту в стандарте получился бы бред). P — не что иное, как type of function parameter of function template. Надеюсь, то, что следующая программа

struct X {};

X const f();

template <class T>
    int g(T &);

int main()
{
    sizeof g(f());
}

является well-formed, и то, что здесь шаблонным аргументом является const X, сомнений не вызывает.
Re[14]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 19.12.09 10:40
Оценка: 14 (1)
Здравствуйте, Николай Ивченков, Вы писали:

НИ>Юрий Жмеренецкий:


ЮЖ>>Ведь в качестве аргумента, передаваемого в 'g' выступает некоторое значение, а не тип и не выражение некоторого типа.


НИ>Этот тезис нуждается в обосновании.

НИ>

1.3.1 argument
НИ>an expression in the comma-separated list bounded by the parentheses in a function call expression, a sequence of preprocessing tokens in the comma-separated list bounded by the parentheses in a function-like macro invocation, the operand of throw, or an expression, type-id or template-name in the comma-separated list bounded by the angle brackets in a template instantiation. Also known as an actual argument or actual parameter.


Под 'argument passing' понимается не 'expression passing', а инициализация (8.5.3/2). Если initializer expression является rvalue, то объект (параметр) будет инициализирован его значением (8.5/14, возможно косвенно в некоторых случаях). Вот это я имел ввиду (хотя там формулировка не совсем удачная).

В момент инициализации вид выражения является значимым, но в процессе вывода template arguments это не имеет значения (в рассматриваемом примере). Но в 14.8.2.1 сказано следующее:


14.8.2.1/1
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below



14.8.2.1/2
If P is not a reference type:
...
— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.


Это как раз описывает наш случай.

PS: В первоначальном примере msvc с /Za выводит тип как 'int' и выбирает void g(double).
Re[2]: const char* const - Путаница
От: igna Россия  
Дата: 14.12.09 13:52
Оценка: 7 (1)
Здравствуйте, Bell, Вы писали:

B>Достаточно возвращать из функции char const*


Кстати по поводу избыточного const. Вот два объявления:

const char* const GetName();
const int GetNumber();


В первом избыточный const находится справа в имени типа, в втором — слева. Альтернативная форма позиции const более последовательна:

char const* const GetName();
int const GetNumber();


Означает совершенно то же самое, но избыточный const находится справа в обоих случаях, что позволяет сформулировать простое правило: "const непосредственно перед именем функции избыточен".
Re[11]: const char* const - Путаница
От: Николай Ивченков  
Дата: 17.12.09 00:37
Оценка: 7 (1)
rg45:

R>Вот выдержки из стандарта подкрепляющие сказанное:

R>

R>3.10/5
R>The result of calling a function that does not return a reference is an rvalue.

R>

R>3.10/9
R>Class rvalues can have cv-qualified types; non-class rvalues always have cv-unqualified types.

R>Т.е. что есть модификатор const при non-class rvalue, что нет — все равно объект будет cv-unqualified, в этом случае модификатор действительно избыточен.

Это правило в 3.10/9 конфликтует с 5.2.2/3 — "The type of the function call expression is the return type of the statically chosen function" — где о снятии с типа возврата cv-qualifier ничего не сказано. Причём VC++ 9.0 и GNU C++ 4.1.2 в этом отношении строго подчиняются именно 5.2.2/3:

int f1();
int const f2();
 
template <class T>
    void g(T &);
int g(double);

int main()
{
    sizeof g(f1());
    sizeof g(f2()); // VC++ & GNU C++: T is deduced to be 'const int'
}

Также можно отметить, что типы функций f1 и f2 в любом случае разные:

int f1() { return 0; }
int const f2() { return 0; }

int main()
{
    int (&r1)() = f1;
    int (&r2)() = f2; // ill-formed
}
Re: const char* const - Путаница
От: jazzer Россия Skype: enerjazzer
Дата: 13.12.09 03:54
Оценка: 6 (1)
Здравствуйте, TheAteist, Вы писали:

TA>"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?

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

TA>Но вот таким образом у меня получается изменить значение m_name с "name1" на "name2"

Ну правильно, потому что ты используешь явный хак, который тебе пришлось руками написать и который хорошо виден.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: const char* const - Путаница
От: rg45 СССР  
Дата: 16.12.09 23:10
Оценка: 4 (1)
Здравствуйте, igna, Вы писали:

I>Здравствуйте, c-smile, Вы писали:


I>
CS>>T const function();
CS>>const T function();
I>


CS>>я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?


I>Да, const избыточен в обоих случаях, если T имя типа, а не placeholder.


Я бы не был так категоричен. В моем понимании "избыточен" означает "ничего не меняет". Т.е. какой-либо элемент избыточен, если от его наличия или отсутствия ничего не меняется. Если же возвращаемым типом функции является тип-класс, то без модификатора const для результата можно вызывать неконстантные методы, а с модификатором const — только константные. Т.е. разница есть, все-таки.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 14.12.09 04:10
Оценка: 1 (1)
Здравствуйте, Bell, Вы писали:

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


TA>>"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?


B>Функция GetName возвращает константный указатель на константную строку. В принципе первый const избыточен, а вот второй как раз защищает возвращаемый объект (строку) от модификаций.


"О сколько их упало в эту бездну..."

http://duramecho.com/ComputerInformation/WhyHowCppConst.html
Re[5]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 14.12.09 06:54
Оценка: +1
Здравствуйте, x905, Вы писали:

X>не совсем в тему, но предлагаю перейти на "классовые" строки типа QString — проблем будет меньше


Это совсем не в тему.

Слепое использование QString или std::string в тех местах где можно обойтись просто const wchar_t* или slice<wchar_t>
может привести к одной но зело неприятной проблеме — перерасход и/или фрагментация heap.

Если понятие const char* вызывает проблемы то имхо следует уже переходить на .NET/Java. Там во всяком случае не будет фрагментации.
Re[11]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 16.12.09 20:12
Оценка: +1
Здравствуйте, igna, Вы писали:

I>Здравствуйте, c-smile, Вы писали:


CS>>Что такое placeholder в этом случае? Вот это:


I>
CS>>const char* function();
I>


I>Здесь нет никакого placeholder-а.


Т.е. здесь const избыточен? Я правильно следую логике рассуждений?

...

CS>>Т.е. вот это


I>
CS>>collection coll;
CS>>coll[2].mutating_method(); 
I>


CS>>вызовет ошибку компиляции


I>Зато вот это не вызовет:


I>
I>void f(value v)
I>{
I>    v.mutating_method();
I>}

I>collection coll;
I>f(coll[2]);
I>


I>То есть твоя "крайне полезная" защита практически бесполезна.


Ты не понял идею.

Объявив функцию так:

void f(value v)


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

Если же твоя функция объявлена как
void f(value& v)


То вот это:

collection coll;
f(coll[2]);


вызовет ошибку.

А такая функция:

void f(const value& v)


нет.

I>


I>И все же есть один случай, когда const в этом месте может иметь смысл, а именно в случае, если возвращается объект proxy-класса, но в этом случае имя этого класса не должно использоваться пользователем (даже если он видит его в файле заголовка и формально может использовать его). Что ж, в C++ из каждого правила есть исключения.


Ну т.е. ты больше не настаиваешь на своем утверждении:
"const непосредственно перед именем функции избыточен".
Я правильно тебя понял?
Re[6]: const char* const - Путаница
От: joe_kidd  
Дата: 18.12.09 13:17
Оценка: +1
CS>Здравствуйте, x905, Вы писали:

X>>не совсем в тему, но предлагаю перейти на "классовые" строки типа QString — проблем будет меньше

CS> Это совсем не в тему.

CS>Слепое использование QString или std::string в тех местах где можно обойтись просто const wchar_t* или slice<wchar_t>

CS>может привести к одной но зело неприятной проблеме — перерасход и/или фрагментация heap.

По моему совет то как раз именно в тему — сишные массивы нужно использовать только когда они действительно необходимы.
И вместо них нужно использовать врапперы (в данном случае std::string) и не только для возврата результата, но и для полей внутри класса.
Преимущества:
— нет проблем с размерами (не нужно заботиться о расширении и выходе за границу массива),
— удобные операции конкатенации, поиска, прохода по контейнеру
Недостатки:
— уже указанная фрагментация кучи процесса и как следствие — тормоза при выделении памяти из кучи.

Отсюда мой вывод — использовать всегда врапперы, пока тесты не начинают показывать что производительность не соответствует требованиям к продукту.
И то в этом случае можно перейти на аллокаторы отдающие память не из кучи а из пула на стеке.
Короче, как говорится:
"
1. сделай чтобы это работало,
2. сделай чтобы это работало правильно
3. и только потом сделай чтобы это работало быстро".

И вообще — берем "Стандарты программирования на C++" Александреску и Саттера и смотрим совет 77 "Вместо массивов используйте vector и string":

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


CS>Если понятие const char* вызывает проблемы то имхо следует уже переходить на .NET/Java. Там во всяком случае не будет фрагментации.

А если:
— плюсы корпоративный стандарт,
— куча кода на C++
— весь third party API — плюсовый
Да и есть ли в .NET/Java такие же удобные алгоритмы и boost как в плюсах?
const char* const - Путаница
От: TheAteist  
Дата: 12.12.09 20:58
Оценка:
"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?
class Device
{
...
private:    
    char m_name[20];
public:
...
    const char* const GetName() const;
}

Но вот таким образом у меня получается изменить значение m_name с "name1" на "name2"
Device d("name1");
strcpy((char*)d.GetName(),"name2");

Или я не правильно понял "const char* const". Поясниете плиз.

Спасибо.
Re: const char* const - Путаница
От: wander  
Дата: 12.12.09 21:01
Оценка:
Здравствуйте, TheAteist, Вы писали:

TA>Но вот таким образом у меня получается изменить значение m_name с "name1" на "name2"

TA>
TA>Device d("name1");
TA>strcpy((char*)d.GetName(),"name2");
TA>

TA>Или я не правильно понял "const char* const". Поясниете плиз.

Очевидно, ты не правильно понял смысл (char*). Именно этим ты нарушил существующие правила для контроля типов в С++, сделав принудительное приведение типа. Следовательно все последствия налицо.

TA>Спасибо.
Re: const char* const - Путаница
От: Bell Россия  
Дата: 14.12.09 02:52
Оценка:
Здравствуйте, TheAteist, Вы писали:

TA>"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?


Функция GetName возвращает константный указатель на константную строку. В принципе первый const избыточен, а вот второй как раз защищает возвращаемый объект (строку) от модификаций.

TA>Но вот таким образом у меня получается изменить значение m_name с "name1" на "name2"

TA>
TA>Device d("name1");
TA>strcpy((char*)d.GetName(),"name2");
TA>


Против лома нет приема — ты своими руками снял константность с результата GetName — компилятор после этого умывает руки

TA>Или я не правильно понял "const char* const". Поясниете плиз.

Достаточно возвращать из функции char const*, ну и не использовать лом там, где не нужно
Любите книгу — источник знаний (с) М.Горький
Re[3]: const char* const - Путаница
От: Bell Россия  
Дата: 14.12.09 04:32
Оценка:
Здравствуйте, c-smile, Вы писали:

TA>>>"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?


B>>Функция GetName возвращает константный указатель на константную строку. В принципе первый const избыточен, а вот второй как раз защищает возвращаемый объект (строку) от модификаций.


CS>"О сколько их упало в эту бездну..."


Второй (самый правый) const конечно же.
В свое оправдание могу сказать, что финальный ответ все-таки верный

Достаточно возвращать из функции char const*...


Любите книгу — источник знаний (с) М.Горький
Re[4]: const char* const - Путаница
От: x905  
Дата: 14.12.09 06:04
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, c-smile, Вы писали:


TA>>>>"const char* const" в функции GetName() надо чтоб зажитит m_name, т.е. чтоб не изменить его значение?


не совсем в тему, но предлагаю перейти на "классовые" строки типа QString — проблем будет меньше
Re[6]: const char* const - Путаница
От: x905  
Дата: 14.12.09 13:54
Оценка:
Здравствуйте, c-smile, Вы писали:

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


X>>не совсем в тему, но предлагаю перейти на "классовые" строки типа QString — проблем будет меньше


CS>Это совсем не в тему.


CS>Слепое использование QString или std::string в тех местах где можно обойтись просто const wchar_t* или slice<wchar_t>

CS>может привести к одной но зело неприятной проблеме — перерасход и/или фрагментация heap.

можно пример, приводящей к такой фрагментации и как это решается без фрагментации средствами char* ?

также "классовые" строки предоставляют удобные средства по их обработке внутри класса, и есть вспомогательные, например qregexp
Re[3]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 14.12.09 17:16
Оценка:
Здравствуйте, igna, Вы писали:

I>Означает совершенно то же самое, но избыточный const находится справа в обоих случаях, что позволяет сформулировать простое правило: "const непосредственно перед именем функции избыточен".


Это еще почему?
Re[7]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 14.12.09 17:40
Оценка:
Здравствуйте, x905, Вы писали:

X>можно пример, приводящей к такой фрагментации и как это решается без фрагментации средствами char* ?


Хмм... грешным делом думал это очевидно.

Вот тебе пример: http://www.codeproject.com/KB/recipes/HTML_XML_Scanner.aspx

Этот xml scanner и приведенная в статье тестовая программа в процессе
работы не аллоцируют памяти. В смысле вообще. Какого бы размера входной файл не был.

X>также "классовые" строки предоставляют удобные средства по их обработке внутри класса, и есть вспомогательные, например qregexp


Да, в C++ можно объявить классы и у них описать методы. Ты этот факт имел ввиду?
Или что-то конкретное? Как-то std::string и "удобные средства по их обработке внутри класса" слабо вяжутся.
Re[4]: const char* const - Путаница
От: igna Россия  
Дата: 14.12.09 20:17
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Это еще почему?


Это потому. У тебя есть контрпример?
Re[8]: const char* const - Путаница
От: x905  
Дата: 15.12.09 05:49
Оценка:
Здравствуйте, c-smile, Вы писали:

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


X>>можно пример, приводящей к такой фрагментации и как это решается без фрагментации средствами char* ?

CS>Хмм... грешным делом думал это очевидно.
CS>Вот тебе пример: http://www.codeproject.com/KB/recipes/HTML_XML_Scanner.aspx
CS>Этот xml scanner и приведенная в статье тестовая программа в процессе
CS>работы не аллоцируют памяти. В смысле вообще. Какого бы размера входной файл не был.

хотелось бы увидеть пример когда использование QString | std::string приводило бы к неприятной фрагментации памяти , а char* нет

указанный пример (http://www.codeproject.com/KB/recipes/HTML_XML_Scanner/xh_scanner_demo.zip) не работает, если, например, в main в si добавить русскую букву в UTF8 (не у всех же венда стоит с однобайтовой кодировкой) — это из-за "ползанья" по строке с помощью p++
вот и глюк нашелся

X>>также "классовые" строки предоставляют удобные средства по их обработке внутри класса, и есть вспомогательные, например qregexp


CS>Да, в C++ можно объявить классы и у них описать методы. Ты этот факт имел ввиду?

CS>Или что-то конкретное? Как-то std::string и "удобные средства по их обработке внутри класса" слабо вяжутся.

конкретно QString
Re[9]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 15.12.09 06:25
Оценка:
Здравствуйте, x905, Вы писали:

X>хотелось бы увидеть пример когда использование QString | std::string приводило бы к неприятной фрагментации памяти , а char* нет


Вот тебе живой пример:
http://pavlovdotnet.wordpress.com/2007/11/10/memory-fragmentation/

Это реальная проблема и не важно что именно ты используешь QString или nsString

X>указанный пример (http://www.codeproject.com/KB/recipes/HTML_XML_Scanner/xh_scanner_demo.zip) не работает, если, например, в main в si добавить русскую букву в UTF8 (не у всех же венда стоит с однобайтовой кодировкой) — это из-за "ползанья" по строке с помощью p++

X>вот и глюк нашелся

Программеры спеки/доки не читают, да. Даже если текста там всего ничего.

The given scanner does not address any input stream encoding problems.


X>конкретно QString


Конекретно QString аллоцирует две версии строки в виде char* и wchar* в одном instance QString что делает проблему фрагментации серьёзнее ровно в два раза. В server side и 24/7 системах такое использовать не надо.
Re[5]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 15.12.09 06:28
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, c-smile, Вы писали:


CS>>Это еще почему?


I>Это потому. У тебя есть контрпример?


Ты считаешь что const в

const T function();


всегда избыточен. Я правильно тебя понял?
Re[6]: const char* const - Путаница
От: Bell Россия  
Дата: 15.12.09 06:36
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Ты считаешь что const в


CS>
CS>const T function();
CS>


CS>всегда избыточен. Я правильно тебя понял?


Вообще — то изначально было так:

Альтернативная форма позиции const более последовательна:

char const* const GetName();
int const GetNumber();

Означает совершенно то же самое, но избыточный const находится справа в обоих случаях, что позволяет сформулировать простое правило: "const непосредственно перед именем функции избыточен".


Таким образом, если твою запись переделеть так:
T const function();

то я склонен согласиться с igna.
Любите книгу — источник знаний (с) М.Горький
Re[7]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 15.12.09 07:08
Оценка:
Здравствуйте, Bell, Вы писали:

B>Таким образом, если твою запись переделеть так:

B>
B>T const function();
B>

B>то я склонен согласиться с igna.

Бррр.... всё, я совсем запутался.

Вот две эквивалентные формы описания возвращаемого значения:

T const function();
const T function();


я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?
Re[10]: const char* const - Путаница
От: x905  
Дата: 15.12.09 07:12
Оценка:
Здравствуйте, c-smile, Вы писали:

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

X>>хотелось бы увидеть пример когда использование QString | std::string приводило бы к неприятной фрагментации памяти , а char* нет
CS>Вот тебе живой пример:
CS>http://pavlovdotnet.wordpress.com/2007/11/10/memory-fragmentation/

ок, позже почитаю повнимательнее

касательно char* строк: лично я их стараюсь избегать (как и адресной арифметике) — для меня от них проблем больше чем преимуществ, и наоборот используя QString я получаю больше преимуществ, чем недостатков
о чем и предложил топикастеру, немного отойдя от темы )
Re[11]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 15.12.09 07:24
Оценка:
Здравствуйте, x905, Вы писали:

X>касательно char* строк: лично я их стараюсь избегать (как и адресной арифметике) — для меня от них проблем больше чем преимуществ, и наоборот используя QString я получаю больше преимуществ, чем недостатков

X>о чем и предложил топикастеру, немного отойдя от темы )

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

Ну детский сад какой-то право слово. Тебе даден инструмент ты или им пользуйся профессионально или займись уже .NETом каким что-ли.
В C/C++ без указателей никак.
Re[12]: const char* const - Путаница
От: x905  
Дата: 15.12.09 08:45
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>1) Ножик, он хоть и острый, но вельми полезный бывает.

CS>2) Советы не использовать ножики в быту надо сопровождать чеками на соответсвующие суммы позволяющие нанять людей которые будут для тебя точить твои карандаши пока ты творишь.

так ведь есть такие иструменты — тотже QString например (и денег не просит)
и да я буду дальше творить, а не затачиваться на указателях на char

CS>Ну детский сад какой-то право слово. Тебе даден инструмент ты или им пользуйся профессионально или займись уже .NETом каким что-ли.

CS>В C/C++ без указателей никак.

в С++ без классов никак
Re[8]: const char* const - Путаница
От: igna Россия  
Дата: 15.12.09 09:10
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>T const function();
CS>const T function();


CS>я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?


Да, const избыточен в обоих случаях, если T имя типа, а не placeholder.
Re[8]: const char* const - Путаница
От: Bell Россия  
Дата: 15.12.09 09:29
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Бррр.... всё, я совсем запутался.


CS>Вот две эквивалентные формы описания возвращаемого значения:


CS>
CS>T const function();
CS>const T function();
CS>


CS>я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?

Правильно.
Вот пример:
struct I {};

typedef I& RInt;

const RInt f1();
RInt const f2();

int main()
{
   I& ri = f1();
   return 0;
}


Comeau:
"ComeauTest.c", line 9: warning: type qualifiers are meaningless in this declaration
const RInt f1();
^

"ComeauTest.c", line 10: warning: type qualifiers are meaningless in this
declaration
RInt const f2();
^


Но это, как это обычно бывает, существуют исключения
здесь
Автор:
Дата: 21.09.04
Любите книгу — источник знаний (с) М.Горький
Re[9]: const char* const - Путаница
От: igna Россия  
Дата: 15.12.09 09:43
Оценка:
Здравствуйте, Bell, Вы писали:

B>Но это, как это обычно бывает, существуют исключения

B>здесь
Автор:
Дата: 21.09.04


Хотя и в этом случае const остается избыточным в том смысле, что его легко обойти не прибегая к const_cast:

    ++C(f());
Re[9]: const char* const - Путаница
От: c-smile Канада http://terrainformatica.com
Дата: 15.12.09 19:02
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, c-smile, Вы писали:


I>
CS>>T const function();
CS>>const T function();
I>


CS>>я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?


I>Да, const избыточен в обоих случаях, если T имя типа, а не placeholder.


Что такое placeholder в этом случае? Вот это:

const char* function();


к какой категории относится? placeholder или имя типа?


Далее, скажем вот есть такая конструкция:

class collection
{
  ...
  const value operator[](int i) const { return get_item_at(i); } 
}


Я например нахожу const value объявление в данном случае крайне полезным.

Т.е. вот это

collection coll;
coll[2].mutating_method();


вызовет ошибку компиляции, а вот это:
collection coll;
coll[2].const_method();


вполне себе легитимная конструкция.
Re[10]: const char* const - Путаница
От: igna Россия  
Дата: 16.12.09 07:53
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Что такое placeholder в этом случае? Вот это:


CS>const char* function();


Здесь нет никакого placeholder-а.




CS>Далее, скажем вот есть такая конструкция:


CS>class collection
CS>{
CS>  ...
CS>  const value operator[](int i) const { return get_item_at(i); } 
CS>}


CS>Я например нахожу const value объявление в данном случае крайне полезным.


CS>Т.е. вот это


CS>collection coll;
CS>coll[2].mutating_method();


CS>вызовет ошибку компиляции



Зато вот это не вызовет:

void f(value v)
{
    v.mutating_method();
}

collection coll;
f(coll[2]);


То есть твоя "крайне полезная" защита практически бесполезна.

На самом деле нужно передавать и возвращать ссылку на const value, но тогда const нельзя записать непосредственно перед именем функции и правило "const непосредственно перед именем функции избыточен" остается в силе.




И все же есть один случай, когда const в этом месте может иметь смысл, а именно в случае, если возвращается объект proxy-класса, но в этом случае имя этого класса не должно использоваться пользователем (даже если он видит его в файле заголовка и формально может использовать его). Что ж, в C++ из каждого правила есть исключения.
Re[10]: const char* const - Путаница
От: rg45 СССР  
Дата: 16.12.09 23:29
Оценка:
Здравствуйте, rg45, Вы писали:

I>>
CS>>>T const function();
CS>>>const T function();
I>>


CS>>>я правильно понял что общественность настаивает на том что const у возвращаемого значения избыточен?


I>>Да, const избыточен в обоих случаях, если T имя типа, а не placeholder.


R>Я бы не был так категоричен. В моем понимании "избыточен" означает "ничего не меняет". Т.е. какой-либо элемент избыточен, если от его наличия или отсутствия ничего не меняется. Если же возвращаемым типом функции является тип-класс, то без модификатора const для результата можно вызывать неконстантные методы, а с модификатором const — только константные. Т.е. разница есть, все-таки.


Вот выдержки из стандарта подкрепляющие сказанное:

3.10/5
The result of calling a function that does not return a reference is an rvalue.

3.10/9
Class rvalues can have cv-qualified types; non-class rvalues always have cv-unqualified types.

Т.е. что есть модификатор const при non-class rvalue, что нет — все равно объект будет cv-unqualified, в этом случае модификатор действительно избыточен. А вот для class rvalues наличие const или volatile имеет значение.
--
Справедливость выше закона. А человечность выше справедливости.
Re[12]: const char* const - Путаница
От: igna Россия  
Дата: 17.12.09 09:08
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>>>const char* function();


CS>Т.е. здесь const избыточен? Я правильно следую логике рассуждений?


Нет. Он разве находится "непосредственно перед именем функции" или может быть перемещен туда?




CS>Объявив функцию так:


CS>void f(value v)


CS>ты явным образом попросил создать копию параметра. С копией не возбраняется делать что угодно.


Если существует причина приводящая к необходимости запрета на изменение возвращаемого временного значения (например потому-что значение это является proxy, вызов не const-метода для которого приводит к изменению некоторого другого объекта, изменение которого мы хотели бы предотвратить), то вызов не const-метода копии приведет точно к тому же нежелательному результату. То есть если уж, то конструктор копирования нужно сделать не-public.




CS>Ну т.е. ты больше не настаиваешь на своем утверждении:

CS>"const непосредственно перед именем функции избыточен".
CS>Я правильно тебя понял?

Нет.

Серьезно, несмотря на неоднозначность такого ответа или возможно как раз благодаря ей. Правило "const непосредственно перед именем функции избыточен" верно в 999 случаях из 1000. Кроме того не надо забывать, что я сформулировал его только для определенного стиля использования const, а именно когда const указывается как можно правее.
Re[12]: const char* const - Путаница
От: igna Россия  
Дата: 17.12.09 09:11
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

[off-topic]

Ответь пожалуйста на вопрос, как адекватно перевести "function parameter" здесь
Автор: igna
Дата: 08.12.09
.
Re[12]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 18.12.09 11:41
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

R>>Вот выдержки из стандарта подкрепляющие сказанное:

...
R>>

R>>3.10/9
R>>Class rvalues can have cv-qualified types; non-class rvalues always have cv-unqualified types.

R>>Т.е. что есть модификатор const при non-class rvalue, что нет — все равно объект будет cv-unqualified, в этом случае модификатор действительно избыточен.

НИ>Это правило в 3.10/9 конфликтует с 5.2.2/3 — "The type of the function call expression is the return type of the statically chosen function" — где о снятии с типа возврата cv-qualifier ничего не сказано. Причём VC++ 9.0 и GNU C++ 4.1.2 в этом отношении строго подчиняются именно 5.2.2/3:


НИ>
int f1();
НИ>int const f2();
 
НИ>template <class T>
НИ>    void g(T &);
НИ>int g(double);

НИ>int main()
НИ>{
НИ>    sizeof g(f1());
НИ>    sizeof g(f2()); // VC++ & GNU C++: T is deduced to be 'const int'
НИ>}


Я не вижу здесь противоречия. Ведь в качестве аргумента, передаваемого в 'g' выступает некоторое значение, а не тип и не выражение некоторого типа. Но т.к. это значение представляет из себя 'non-class rvalue', то квалификатор с него должен быть снят, и только после этого тип аргумента начнет фигурировать в процессе overload resolution (для 'g').
Re[13]: const char* const - Путаница
От: Николай Ивченков  
Дата: 18.12.09 12:05
Оценка:
Юрий Жмеренецкий:

ЮЖ>Ведь в качестве аргумента, передаваемого в 'g' выступает некоторое значение, а не тип и не выражение некоторого типа.


Этот тезис нуждается в обосновании.

1.3.1 argument
an expression in the comma-separated list bounded by the parentheses in a function call expression, a sequence of preprocessing tokens in the comma-separated list bounded by the parentheses in a function-like macro invocation, the operand of throw, or an expression, type-id or template-name in the comma-separated list bounded by the angle brackets in a template instantiation. Also known as an actual argument or actual parameter.

ЮЖ>Но т.к. это значение представляет из себя 'non-class rvalue'

Значения не делятся на lvalue и rvalue. Lvalue и rvalue — это виды выражений:

3.10 Lvalues and rvalues
1 Every expression is either an lvalue or an rvalue.

Re[6]: const char* const - Путаница
От: rg45 СССР  
Дата: 18.12.09 13:44
Оценка:
Здравствуйте, c-smile, Вы писали:

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


X>>не совсем в тему, но предлагаю перейти на "классовые" строки типа QString — проблем будет меньше


CS>Это совсем не в тему.


CS>Слепое использование QString или std::string в тех местах где можно обойтись просто const wchar_t* или slice<wchar_t>

CS>может привести к одной но зело неприятной проблеме — перерасход и/или фрагментация heap.

std::string и подобные классы как раз и существуют для использования по умолчанию, т.е. именно для слепого использования. Случаи, когда грамотное использование этих классов приводят к проблемам производительности на практике можно считать скорее исключением, чем правилом. А вот слепое использование голых указателей в том месте, где можно использовать умные обертки, может привести к проблемам во сто крат более серьезным — неустойчивость по отношению к исключениям, утечки памяти, что чревато настоящим перерасходом.

CS>Если понятие const char* вызывает проблемы то имхо следует уже переходить на .NET/Java. Там во всяком случае не будет фрагментации.


Не вызывает понятие const char* никаких проблем. Ассемблер, например, тоже не вызывает проблем с пониманием — выбираем ассемблер стандартным инструментом разработки?
--
Справедливость выше закона. А человечность выше справедливости.
Re[15]: const char* const - Путаница
От: Николай Ивченков  
Дата: 19.12.09 12:06
Оценка:
Юрий Жмеренецкий:

ЮЖ>Под 'argument passing' понимается не 'expression passing', а инициализация (8.5.3/2). Если initializer expression является rvalue, то объект (параметр) будет инициализирован его значением (8.5/14, возможно косвенно в некоторых случаях). Вот это я имел ввиду (хотя там формулировка не совсем удачная).


Как это влияет на вывод шаблонных аргументов?

ЮЖ>Но в 14.8.2.1 сказано следующее:

ЮЖ>

14.8.2.1/1
ЮЖ>Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below

ЮЖ>

14.8.2.1/2
ЮЖ>If P is not a reference type:
ЮЖ>...
ЮЖ>— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

ЮЖ>Это как раз описывает наш случай.

В нашем случае P — это T &, что определённо есть reference type.
Re[16]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 19.12.09 13:30
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

НИ>Юрий Жмеренецкий:


ЮЖ>>Под 'argument passing' понимается не 'expression passing', а инициализация (8.5.3/2). Если initializer expression является rvalue, то объект (параметр) будет инициализирован его значением (8.5/14, возможно косвенно в некоторых случаях). Вот это я имел ввиду (хотя там формулировка не совсем удачная).


НИ>Как это влияет на вывод шаблонных аргументов?

Здесь — никак, я уже сказал об этом.

ЮЖ>>Но в 14.8.2.1 сказано следующее:

ЮЖ>>

14.8.2.1/1
ЮЖ>>Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below

ЮЖ>>

14.8.2.1/2
ЮЖ>>If P is not a reference type:
ЮЖ>>...
ЮЖ>>— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

ЮЖ>>Это как раз описывает наш случай.

НИ>В нашем случае P — это T &


Это неверно. Возьми хотя бы 14.1:

template-declaration:
  export_opt template < template-parameter-list > declaration
                                                      \--- 'void g(T& x)'

template-parameter-list:
  template-parameter
  template-parameter-list , template-parameter


Из этого определения следует, что появлению template parametr'a должна предшествовать такая конструкция: 'template <'.

В нашем примере так:

template<class T> 
//             \---Template parameter
void g(T& x);
//        \-- Function parameter of a function template
//...
//
g<int>(v); // гипотетический вызов
//  \-------- Template argument
Re[18]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 20.12.09 03:18
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

НИ>Тогда я не понимаю, в чём заключается суть твоего возражения с упоминанием значений.


НИ>Если P — это не T &, то что тогда?


Поетнциально здесь возможны два варианта: квалификатор удаляется при выводе типов, либо уже удален к этому времени. Первоначально я склонялся ко второму варианту. Попытка притянуть за уши 'function template parameter' не выдерживает критики, здесь ты прав.

Собственно остается только вероятность наличия второго варианта, т.к. об удалении квалификаторов с non-class rvalues при выводе типов ничего не сказано. Но с одной стороны — тип выражения однозначно завсит от его вида, с другой — не во всех контекстах эта зависимость используется. Хотя например в 5.4/1, 5.2.3/2 очень похожая ситуация: явно определяется тип выражения (T), но рядом находится примечание:

Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting rvalue (3.10).

Re[18]: const char* const - Путаница
От: igna Россия  
Дата: 20.12.09 09:10
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

НИ>Формулировка "function template parameter type (call it P)", на мой взгляд, выбрана неудачно

. . .
НИ>P — не что иное, как type of function parameter of function template.

"type of function parameter of function template" — это корректный английский?
Re[19]: const char* const - Путаница
От: Николай Ивченков  
Дата: 20.12.09 11:59
Оценка:
Юрий Жмеренецкий:

ЮЖ>Хотя например в 5.4/1, 5.2.3/2 очень похожая ситуация: явно определяется тип выражения (T), но рядом находится примечание:


ЮЖ>

Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting rvalue (3.10).

Здесь та же проблема. Примечания не являются нормативными.

Сравни две формулировки:

1) "non-class rvalues always have cv-unqualified types." (то, что есть)
2) "If an rvalue initially has the cv-qualified type "cv T", where T is non-class type, the type of the rvalue is adjusted to "T" prior to any further analysis." (то, что могло бы быть)

Как видно, не все разработчики компиляторов имеют достаточно телепатических способностей, чтобы трактовать первую формулировку, как вторую.
Re[20]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 21.12.09 01:32
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

ЮЖ>>Хотя например в 5.4/1, 5.2.3/2 очень похожая ситуация: явно определяется тип выражения (T), но рядом находится примечание:


ЮЖ>>

Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting rvalue (3.10).

НИ>Здесь та же проблема. Примечания не являются нормативными.

Разумеется. Но выше тип определяется как 'T', а не как 'type of the resulting rvalue' (притянуто) .

НИ>Сравни две формулировки:


НИ>1) "non-class rvalues always have cv-unqualified types." (то, что есть)

НИ>2) "If an rvalue initially has the cv-qualified type "cv T", where T is non-class type, the type of the rvalue is adjusted to "T" prior to any further analysis." (то, что могло бы быть)

Хм.. И как бы это изменило ситуацию? При выводе типов используется тип аргумента, который эквивалентен типу выражения, а это в свою очередь — "return type of the statically chosen function". Тот факт, что при определении типа resulting rvalue мы получим 'int', проскальзывает мимо.
Re[21]: const char* const - Путаница
От: Николай Ивченков  
Дата: 21.12.09 10:28
Оценка:
Юрий Жмеренецкий:

ЮЖ>Но выше тип определяется как 'T', а не как 'type of the resulting rvalue' (притянуто) .


Я не понял твою мысль.

НИ>>Сравни две формулировки:


НИ>>1) "non-class rvalues always have cv-unqualified types." (то, что есть)

НИ>>2) "If an rvalue initially has the cv-qualified type "cv T", where T is non-class type, the type of the rvalue is adjusted to "T" prior to any further analysis." (то, что могло бы быть)

ЮЖ>Хм.. И как бы это изменило ситуацию?


Точно так же, как и в случае со ссылками:

int &f();
template <class T>
    char g(T);

int main()
{
    sizeof g(f());
}

Согласно тому же 5.2.2/3 здесь изначальным типом выражения f() является "int &". Далее вступает в силу 5/6:

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to “T” prior to any further analysis, the expression designates the object or function denoted by the reference, and the expression is an lvalue.

— таким образом, тип выражения f() корректируется до "int".

ЮЖ>При выводе типов используется тип аргумента, который эквивалентен типу выражения, а это в свою очередь — "return type of the statically chosen function".


"return type of the statically chosen function" относится к начальному типу выражения, который может быть скорректирован. В процессе дедукции за A берётся скорректированный тип. В примере выше это будет "int", а не "int &".
Re[22]: const char* const - Путаница
От: Юрий Жмеренецкий ICQ 380412032
Дата: 21.12.09 12:50
Оценка:
Здравствуйте, Николай Ивченков, Вы писали:

ЮЖ>>Но выше тип определяется как 'T', а не как 'type of the resulting rvalue' (притянуто) .


НИ>Я не понял твою мысль.


У меня есть подозрение, что те компиляторы, которые выводят тип как const int, не учитывают тот факт, что аргументом является rvalue (и поэтому не снимают квалификатор) и используют "return type of the statically chosen function". Поэтому та формулировка, которую ты привел, не может повлиять на это.


НИ>>>1) "non-class rvalues always have cv-unqualified types." (то, что есть)

НИ>>>2) "If an rvalue initially has the cv-qualified type "cv T", where T is non-class type, the type of the rvalue is adjusted to "T" prior to any further analysis." (то, что могло бы быть)

ЮЖ>>Хм.. И как бы это изменило ситуацию?


НИ>Точно так же, как и в случае со ссылками:


<...>

НИ>- таким образом, тип выражения f() корректируется до "int".


И все-таки я не понимаю, чем тебе не нравится 3.10/5:

The result of calling a function that does not return a reference is an rvalue.


В совокупности в "non-class rvalues always have cv-unqualified types." ?

ЮЖ>>При выводе типов используется тип аргумента, который эквивалентен типу выражения, а это в свою очередь — "return type of the statically chosen function".


НИ>"return type of the statically chosen function" относится к начальному типу выражения, который может быть скорректирован. В процессе дедукции за A берётся скорректированный тип.


Тогда в чем выражаются претензии? Ведь изначально ты ссылался на то, что о снятии квалификатора ничего не сказано.
Re[23]: const char* const - Путаница
От: Николай Ивченков  
Дата: 21.12.09 18:23
Оценка:
Юрий Жмеренецкий:

ЮЖ>У меня есть подозрение, что те компиляторы, которые выводят тип как const int, не учитывают тот факт, что аргументом является rvalue (и поэтому не снимают квалификатор) и используют "return type of the statically chosen function". Поэтому та формулировка, которую ты привел, не может повлиять на это.


Type deduction относилось бы к "any further analysis", поэтому компилятор был бы просто обязан учесть тот факт, что аргумент — rvalue, чтобы окончательно установить его тип.

НИ>>"return type of the statically chosen function" относится к начальному типу выражения, который может быть скорректирован. В процессе дедукции за A берётся скорректированный тип.


ЮЖ>Тогда в чем выражаются претензии?


В нормативном тексте стандарта нет формулировки о снятии cv-квалификатора с non-class rvalue. Если лишь утверждение, из которого следует, что cv-квалифицированных non-class rvalues не бывает. В то же время формулировки

"The type of the function call expression is the return type of the statically chosen function" (5.2.2/3) и
"A function call is an lvalue if and only if the result type is a reference." (5.2.2/10)
"Every expression is either an lvalue or an rvalue." (3.10/1)

подразумевают, что образование cv-квалифицированного non-class rvalue возможно. Каким образом разрешается такой парадокс, остаётся только гадать. Для документа, претендующего на название международного стандарта, такая ситуация выглядит просто дико.

В идеале точный тип выражения вообще следовало бы определять сразу в одном подпункте (будь то 5.2.2, 5.2.3 или 5.4), а не посредством корректировок, за которыми нужно лезть в совсем другой раздел стандарта.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.