On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 19:34. Заголовок: Инициализация указателя на функцию и баг MS VC++ 2010


Встретился интересный вопрос. Чтобы он был более понятен, то сначала продемонстрирую на простом примере.

Выражение вида T(), где T - это некоторый тип, называется инициализацией значением, и для скаларных типов это является инициализацией нулем.

Для примера в следующем предложении

int i = int();.

переменная i инициализируется нулем, которой возвращает выражение int().

Поэтому есть различие между двумя предложениями

int *p = new int;

и

int *p = new int();

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

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

Есть определение типа - указатель на функцию, возвращающую тип void и не имеющую параметров. На самом деле не важно, какой тип функции рассматривается. Главное - это то, что определяется указатель на некоторую функцию.

Итак имеем

typedef void ( *pf )();

В этом предложении с помощью typedef определен указатель на функцию, то есть имя pf стало синонимом для типа void ( * )(). Для краткости и удобства в дальнейшем описании новый тип обозначим буквой T.

Теперь представим, что мы хоти объявить объект этого типа T (или pf - как вам удобнее), и инициализировать его по значению вызовом T(), как это делалось с целочисленной переменной i из примера выше. Когда имеется typedef-определение, то сделать это очень просто:

pf our_pointer = pf();

Как видите, никаких проблем не возникло. Мы объявили объект с именем our_pointer, который имеет тип pf, а в данном случае pf - это синоним для указателя на функцию вида void ( * )(), и инициализировали его нулем, так как, как было уже указано, вызов выражения T() для скалярных типов приводит к инициализации нулем.

Все просто. Но это просто лишь потому, что было typedef-объявление, которое это нам все позволило так легко сделать. А как тоже самое проделать без typedef?

Казалось бы можно записать так

void ( *our_pointer )() = ( void ( * )() )();

Однако такая запись некорректна, так как конструкцию вида T() можно вызывать лишь для простых спецификаторов типа, для определений типов с помощью typedef, или для классов.

Что тогда делать?

На помощь приходит новый спецификатор стандарта С++ 2011 decltype. С помощью него можно решить данную проблему. Хотя код и выглядет вычурно, но тем не менее он не противоречит стандарту С++ 2011

void ( *our_pointer )() = decltype( our_pointer )();

На первый взгляд кажется, что написано нечто несуразное. Мы объявляем переменную, и еще не успев закончить предложение, уже ее имя используем для инициализации ее самой!
Но дело в том, что согласно стандарту переменная сразу же становится видимой после определения ее полного декларатора. В данном случае полным декларатором переменной our_pointer является выражение void ( *our_pointer )() в левой части предложения. Поэхтому в правой части после оператора = имя our_pointer уже считается определенным, а потому decltype в состоянии вывести тип этой переменной. А делее все просто: мы получили тип нашего указателя и запустили его "конструктор" с помощью указания пустых круглых скобок после имени типа. Это приводит к инициализации нашего указателя нулем.

Конечно можно было бы и проще сделать, не мучаясь, сразу же присвоив 0 указателю. Но изначально вопрос ставился именно так: как инициализировать указатель на функцию с помощью выражения T(), где T - это тип этого указателя.

К сожалению приходится в очередной раз константировать, что MS VC++ 2010 этот код не компилирует, хотя никаких проблем с компиляцией этого кода не возникает у онлайнового компилятора

В этом можно убедиться, введя такой простой пример

#include <iostream> 

int main()
{
void ( *our_pointer )() = decltype( our_pointer )();

std::cout << "our_pointer = " << our_pointer << std::endl;

return ( 0 );
}


В Майкрософт же я пошлю сообщение о баге, и подождем, что они ответят по этому поводу.

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 3 [только новые]





ссылка на сообщение  Отправлено: 28.07.12 19:35. Заголовок: Пришел ответ от майк..


Пришел ответ от майкрософт на этот баг компилятора.


 цитата:
Posted by Microsoft on 30.03.2012 at 16:48

Thank you for your defect report. We're happy to say that the issue has been fixed and the fix will be part of the next release.

Tanveer Gani
Visual C++ Team.



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

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 19:36. Заголовок: Сыроежка я тебя раз..


Сыроежка
я тебя разблокировал на programmersforum.ru за неимением адекватных людей. если не сложно, обрати внимание на тему
http://programmersforum.ru/showthread.php?t=194091
и высказывания товарища _Bers

Спасибо: 0 
Цитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 19:37. Заголовок: Мне представляется, ..


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

Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 19
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет