Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
Не выдёргивается толкование. Сказано, что "void * - указатель на данные любого типа, и он приводится к указателю любого типа". С первой частью фразы всё нормально. А со второй - что такое "указатель любого типа"? Как построить фразу, если действительно нужно было бы утверждать, что некий указатель приводится к указателю не только на данные? Так и построить, как stringo это сделал, ведь - верно?
Простак(извини - как представился), в случае подобного выкрутаса на PL/1, была бы ошибка Protection Violation at ...
Ну, не умеет ни один нормальный компилятор такую патологию разруливать. Извини еще раз.
Виноват, С умеет. Деструктор срабатывает.
Простак(извини - как представился), в случае подобного выкрутаса на PL/1, была бы ошибка Protection Violation at ...
Ну, не умеет ни один нормальный компилятор такую патологию разруливать. Извини еще раз.
Виноват, С умеет. Деструктор срабатывает.
При чём тут PL/1?
Здесь никакая не патология, а небрежно составленное утверждение. Для C++ - ещё и неверное. Не приводится в C++ указатель на void к указателю на другой тип данных без всякого предупреждения. Более того, это трактуется как ошибка, а не как предупреждение.
В C нет деструкторов.
В C нет деструкторов.
simpleton:
В C/C++ есть ещё применения для типа void. Например, void * - указатель на данные любого типа. Такой указатель приводится к указателю любого типа безо всякого предупреждения
C:
Компилятор ругается вполне определённым образом:
C++:
Компилятор также ругается вполне определённым образом в обоих случаях:Кстати, так и не ответили на вопрос, как переменные могут считаться использованными, если для изобретённого вида "использования" (есть инициализация - значит, есть использование) при удалении из любой программы переменных, "использованных" именно таким образом, логическое поведение этой любой программы абсолютно не меняется.
Для данных примеров, кстати, для C:
с точки зрения "взрослого" компилятора, переменная f НЕ является использованной, несмотря на то, что она инициализирована.
Для C++:
с точки зрения "взрослого" компилятора, и переменная i, и переменная f, - обе НЕ являются использованными, несмотря на то, что обе инициализированы.
Логика "использованности", по крайней мере, для встроенных типов, очень проста: если значение переменной НЕ прочитано, она НЕ использована.
Именно поэтому "взрослый" компилятор считает, что в обоих случаях переменная p ЯВЛЯЕТСЯ использованной.
У меня это тоже не компилируется:
Вот это компилируется и работает:
Так что, утверждение Славы верно. Указатель типа void* именно приводится к любому типу. Формально, конструктор не приводит к типу, а инициализирует. Если не предусмотрены шаблон или перегрузка конструктора для какого-либо типа, то это не значит, что нельзя привести тип. Это означает, что непредусмотренным типом инициализировать нельзя. Базовые типы указателей не обязаны уметь инициализировать себя через конструктор, чем попало.
Т.е. в Вашем примере отсутствует приведение типа.
У меня это тоже не компилируется:
Видимо, не компилируется строка:
void *p(&p);
Если это так, значит, использованный компилятор не соответствует стандарту C++.
В момент начала инициализации, то есть, когда когда за идентификатором p обнаружена открывающая круглая скобка, переменная уже существует, хоть ещё и не инициализирована, и - более того - для неё выделена память. Действительно, инициализируется значением некая область памяти, а не "воздух", поэтому, к моменту инициализации, память должна быть обязательно выделена. А раз память выделена, то имеется и вполне определённый её адрес, который и является адресом переменной. Соответственно, в выражении, используемом для инициализации, правомерно использовать адрес этой самой инициализируемой переменной. То же самое, кстати, относится и к C.
Касательно С++ и даже того же MQL4++. В конструкторе класса при инициализации объекта в инициализирующей части конструктора (между ":" и "{") точно так же и по той же причине правомерно использовать this, который является адресом - на момент использования this - ещё не инициализированного объекта класса. Например, для того же MQL4++:
В инициализирующей части конструктора был использован this ещё неинициализированного объекта. Тем не менее, данный пример прекрасно компилируется без всяких предупреждений и прекрасно работает:
Вот это компилируется и работает:
Так что, утверждение Славы верно. Указатель типа void* именно приводится к любому типу.
Утверждение звучит следующим образом: "Например, void * - указатель на данные любого типа. Такой указатель приводится к указателю любого типа безо всякого предупреждения".
В утверждении не сказано, какого типа приведение имеется ввиду, явное или неявное. Однако, в утверждении имеется дополнение: "безо всякого предупреждения". Очевидно, что это позволяет вполне обоснованно предполагать, что имелось ввиду именно неявное приведение. В самом деле, возьмём тот же MQL4++:
Компилятор совершенно определённо предупреждает о возможных последствиях при неявном приведении и совсем НЕ предупреждает при явном:
Точно так же в смысле предупреждений при неявном приведении ведут себя и компиляторы C/C++.
Более того, здесь, на форуме, можно встретить неоднократные советы применить явное приведение вместо неявного, чтобы избавиться от предупреждения компилятора о возможных последствиях.
Если нет явного приведения, это ещё не значит, что приведения нет вообще.
Zhunko:
Формально, конструктор не приводит к типу, а инициализирует. Если не предусмотрены шаблон или перегрузка конструктора для какого-либо типа, то это не значит, что нельзя привести тип. Это означает, что непредусмотренным типом инициализировать нельзя. Базовые типы указателей не обязаны уметь инициализировать себя через конструктор, чем попало.
Zhunko:
Т.е. в Вашем примере отсутствует приведение типа.
А как же тогда быть с тем, что компилятор для моего примера выдаёт вполне однозначные сообщения об ошибках? Вот эти:
Одно из двух: или компилятор нагло врёт, ведя речь о какой-то там "conversion" между парой типов 'void*' и 'int*' и парой 'void*' и 'int (*)()', или кто-то ошибся в своём утверждении об отсутствии приведения типа в моём примере.
Скорее всего, кроме небрежности с "любым типом указателя", stringo либо просто ошибся "в направлении приведения" для C++ (это к указателю на void указатель на другой тип данных приводится неявно и без предупреждений) либо забыл, что в C++ с приведениями - строже, чем в C, и неявное приведение там допускается только к указателю на void (в одну сторону, а не в обе).
Видимо, не компилируется строка:
1. Если это так, значит, использованный компилятор не соответствует стандарту C++.
2. В момент начала инициализации, то есть, когда когда за идентификатором p обнаружена открывающая круглая скобка, переменная уже существует, хоть ещё и не инициализирована, и - более того - для неё выделена память. Действительно, инициализируется значением некая область памяти, а не "воздух", поэтому, к моменту инициализации, память должна быть обязательно выделена. А раз память выделена, то имеется и вполне определённый её адрес, который и является адресом переменной. Соответственно, в выражении, используемом для инициализации, правомерно использовать адрес этой самой инициализируемой переменной. То же самое, кстати, относится и к C.
3. В утверждении не сказано, какого типа приведение имеется ввиду, явное или неявное. Однако, в утверждении имеется дополнение: "безо всякого предупреждения". Очевидно, что это позволяет вполне обоснованно предполагать, что имелось ввиду именно неявное приведение. В самом деле, возьмём тот же MQL4++:
Компилятор совершенно определённо предупреждает о возможных последствиях при неявном приведении и совсем НЕ предупреждает при явном:
Точно так же в смысле предупреждений при неявном приведении ведут себя и компиляторы C/C++.
Более того, здесь, на форуме, можно встретить неоднократные советы применить явное приведение вместо неявного, чтобы избавиться от предупреждения компилятора о возможных последствиях.
Если нет явного приведения, это ещё не значит, что приведения нет вообще.
4. У встроенных и производных типов (следует отличать от типов, определяемых пользователем, каковыми являются, например, классы), например, у такого производного типа, как указатель, нет никаких конструкторов. При отсутствии явного приведения, всё, что требуется в данном случае от выражения, использованного для инициализации, - чтобы тип этого выражения был неявно приводим к типу инициализируемой переменной, то есть, к типу указателя на соответствующий тип.
5. А как же тогда быть с тем, что компилятор для моего примера выдаёт вполне однозначные сообщения об ошибках? Вот эти:
Одно из двух: или компилятор нагло врёт, ведя речь о какой-то там "conversion" между парой типов 'void*' и 'int*' и парой 'void*' и 'int (*)()', или кто-то ошибся в своём утверждении об отсутствии приведения типа в моём примере.
6. Скорее всего, кроме небрежности с "любым типом указателя", stringo либо просто ошибся "в направлении приведения" для C++ (это к указателю на void указатель на другой тип данных приводится неявно и без предупреждений) либо забыл, что в C++ с приведениями - строже, чем в C, и неявное приведение там допускается только к указателю на void (в одну сторону, а не в обе).
1. Да, Майкрософт всегда снабжает студию компилятором несоответствующим стандарту С++ :-)) Это обычное дело :-))
2. Компилятор видит переменную, как объявленную, сразу после завершения оператора. Т.е. после ";". Так всегда было.
3. Использование неявного приведения это действие на авось. Вдруг прокатит. Вот у вас в примере не прокатило. Не нашлось подходящего конструктора.
4. Как это, нет конструктора? Если пример ниже компилируется, то конструктор есть.
Все базовые типы имеют конструкторы.
5. У Вас какой-то "левый" компилятор. Или, возможно, сильно устаревший. У меня так:
1>(416): error C2440: инициализация: невозможно преобразовать "void *" в "int *"
1> Для преобразования "void*" к указателю на тип, не являющемуся "void", требуется явное приведение
1>(417): error C2440: инициализация: невозможно преобразовать "void *" в "int (__cdecl *)(void)"
1> Для преобразования "void*" к указателю на тип, не являющемуся "void", требуется явное приведение
Компилятор обнаружил в единственном конструкторе невозможное присваивание. Всё разжевал и сразу предложил сделать явное приведение.
6. Слава всё правильно написал. Суть, повторюсь, в том, что у Вас нет приведения (явного приведения). Неявное можете сами сделать с помощью обёртки для базового типа. Дополните ещё одним конструктором.
1. Да, Майкрософт всегда снабжает студию компилятором несоответствующим стандарту С++ :-)) Это обычное дело :-))
2. Компилятор видит переменную, как объявленную, сразу после завершения оператора. Т.е. после ";". Так всегда было.
3. Использование неявного приведения это действие на авось. Вдруг прокатит. Вот у вас в примере не прокатило. Не нашлось подходящего конструктора.
4. Как это, нет конструктора? Если пример ниже компилируется, то конструктор есть.
Все базовые типы имеют конструкторы.
5. У Вас какой-то "левый" компилятор. Или, возможно, сильно устаревший.
1. Да, это так, но ничего смешного в этом не вижу. Правда, последнее время они начали исправляться, что радует: C++11/14 Core Language Features in VS 2013 and the Nov 2013 CTP.
2. Хоть какие-нибудь аргументы можно увидеть, кроме "так всегда было"?
И заодно объяснить следующее явление, нагло имеющее место не только в C++, но даже в MQL4++:
Которое имеет наглость ещё и работать, как ожидается:
Как хорошо видно, в конструкции "int i = 7, j = i + 1;" для инициализации переменной j в выражении используется даже не адрес, а значение переменной i, хотя до "завершения оператора", то есть, до ";", дело ещё не дошло. Как это сопоставить с "так всегда было"?
Что ж, наверное следует обратиться к первоисточнику и, без преувеличения, - истине в последней инстанции, то есть, к стандарту C++11 (использован текущий драфт N3690):
Совершенно ясно сказано, что точка декларации находится сразу после полного декларатора и до его инициализации, то есть, в моём примере, - на открывающей круглой скобке после имени переменной, как я и говорил. Более того, в только что процитированной мной части стандарта приведён пример, очень близкий к нашему случаю, (во внутреннем блоке, образованном { }) и далее прямо написано, что для этого случая переменная инициализируется своим собственным же (неопределённым) значением. Если уж прямо в стандарте пример приведён, - тут уж никуда не деться...
3. Это не у меня в примере "не прокатило", а утверждение stringo оказалось неверным, мой пример лишь был специально так составлен, чтобы это показать.
4. Хотелось бы ясно увидеть, как из того, что пример компилируется, следует, что конструктор есть. И ссылку на хоть какой-нибудь вменяемый документ, где утверждается, что в C++ все базовые типы имеют конструкторы.
5. gcc version 4.7.2. Не настолько и устаревший.
Zhunko:
У меня так:
1>(416): error C2440: инициализация: невозможно преобразовать "void *" в "int *"
1> Для преобразования "void*" к указателю на тип, не являющемуся "void", требуется явное приведение
1>(417): error C2440: инициализация: невозможно преобразовать "void *" в "int (__cdecl *)(void)"
1> Для преобразования "void*" к указателю на тип, не являющемуся "void", требуется явное приведение
Компилятор обнаружил в единственном конструкторе невозможное присваивание. Всё разжевал и сразу предложил сделать явное приведение.
6. Слава всё правильно написал. Суть, повторюсь, в том, что у Вас нет приведения (явного приведения). Неявное можете сами сделать с помощью обёртки для базового типа. Дополните ещё одним конструктором.
Нет там никакого присваивания, там - инициализация, это сильно разные вещи. Более того, в сообщении об ошибках компилятор об этом прямым текстом и заявляет, цитирую: "error C2440: инициализация:". Инициализация, а не "невозможное присваивание". В сообщениях об ошибках также сказано о том, что, цитирую: "невозможно преобразовать" и "требуется явное приведение". Ничего об обнаружении "невозможного присваивания" там не сказано. И про конструкторы ни слова. Зачем же выдумывать?
6. Я специально привёл пример, чтобы показать, что stringo ошибся. Да, суть в том, что в C++ указатель на void НЕ приводится НЕЯВНО к указателю на тип данных, отличных от типа void. Вот, в обратную сторону - приводится НЕЯВНО, а так, как утверждал stringo - нет.
1. Да, это так, но ничего смешного в этом не вижу. Правда, последнее время они начали исправляться, что радует: C++11/14 Core Language Features in VS 2013 and the Nov 2013 CTP.
2. Хоть какие-нибудь аргументы можно увидеть, кроме "так всегда было"?
И заодно объяснить следующее явление, нагло имеющее место не только в C++, но даже в MQL4++:
Которое имеет наглость ещё и работать, как ожидается:
Как хорошо видно, в конструкции "int i = 7, j = i + 1;" для инициализации переменной j в выражении используется даже не адрес, а значение переменной i, хотя до "завершения оператора", то есть, до ";", дело ещё не дошло. Как же так, ведь "так всегда было"? Неувязочка...
Что ж, наверное следует обратиться к первоисточнику и, без преувеличения, - истине в последней инстанции, то есть, к стандарту C++11 (использован текущий драфт N3690):
Совершенно ясно сказано, что точка декларации находится сразу после полного декларатора и до его инициализации, то есть, в моём примере, - на открывающей круглой скобке после имени переменной, как я и говорил. Более того, в только что процитированной мной части стандарта приведён пример, очень близкий к нашему случаю, (во внутреннем блоке, образованном { }) и далее прямо написано, что для этого случая переменная инициализируется своим собственным же (неопределённым) значением. Если уж прямо в стандарте пример приведён, - тут уж никуда не деться...
3. Это не у меня в примере "не прокатило", а утверждение stringo оказалось неверным, мой пример лишь был специально так составлен, чтобы это показать.
4. Хотелось бы ясно увидеть, как из того, что пример компилируется, следует, что конструктор есть. И ссылку на хоть какой-нибудь вменяемый документ, где утверждается, что в C++ все базовые типы имеют конструкторы.
5. gcc version 4.7.2. Не настолько и устаревший.
Нет там никакого присваивания, там - инициализация, это сильно разные вещи. Более того, в сообщении об ошибках компилятор об этом прямым текстом и заявляет, цитирую: "error C2440: инициализация:". Инициализация, а не "невозможное присваивание".
В сообщениях об ошибках также сказано о том, что, цитирую: "невозможно преобразовать" и "требуется явное приведение". Ничего об обнаружении "невозможного присваивания" там не сказано. И про конструкторы ни слова. Зачем же выдумывать?
6. Я специально привёл пример, чтобы показать, что stringo ошибся. Да, суть в том, что в C++ указатель на тип данных, отличных от типа void, НЕ приводится НЕЯВНО к указателю на void. Вот, в обратную сторону - приводится НЕЯВНО, а так, как утверждал stringo - нет.
Вы сами-то поняли, что сказали?
Вы сами-то поняли, что сказали?