Подтвердить что ты не робот

Почему функция не является объектом?

Я читал в стандартах n4296 (черновик) § 1.8 стр. 7:

Объект - это область хранения. [Примечание. Функция не объекта, независимо от того, занимает ли он хранение в том виде, как объекты. -end note]

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

  • Почему функция не является объектом? Как он отличается?
  • И имеет ли это какое-либо отношение к функторам (объектам функции)?
4b9b3361

Ответ 1

Большая часть разницы сводится к указателям и адресации. В С++ ¹ указатели на функции и указатели на объекты - это строго отдельные виды вещей.

С++ требует, чтобы вы могли преобразовать указатель на любой тип объекта в указатель на void, а затем преобразовать его обратно в исходный тип, и результат будет равен указателю, который вы начали с². Другими словами, независимо от того, как они это делают, реализация должна гарантировать, что преобразование из указателя в объект-тип в pointer-to-void будет без потерь, поэтому независимо от того, что изначально было, любая содержащаяся в нем информация может воссоздан, чтобы вы могли вернуть тот же указатель, с которого вы начали, путем преобразования с T* в void * и обратно на T*.

Это неверно с указателем на функцию, хотя - если вы берете указатель на функцию, преобразуете ее в void *, а затем преобразуете обратно в указатель на функцию, вы можете потерять некоторую информацию в обработать. Вы можете не вернуть исходный указатель, и разыменование того, что вы получите, дает вам поведение undefined (короче говоря, не делайте этого).

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

Хотя это не имеет особого отношения к обсуждаемому вопросу, есть несколько других различий, которые, возможно, стоит отметить. Например, вы можете копировать большинство объектов, но вы не можете копировать какие-либо функции.

Что касается отношения к объектам функции: ну, на самом деле не так много одного за пределами одной точки: объект функции поддерживает синтаксис, который выглядит как вызов функции, но он все еще является объектом, а не функцией. Таким образом, указатель на объект функции по-прежнему является указателем на объект. Если, например, вы конвертируете один из них в void *, а затем преобразуете его обратно в исходный тип, вам все равно гарантируется, что вы вернете исходное значение указателя (что бы не было правдой с указателем на функцию).

Что касается того, почему указатели на функции (по крайней мере потенциально) отличаются от указателей на объекты: часть их сводится к существующим системам. Например, на MS-DOS (среди прочих) было четыре полностью отдельные модели памяти: малые, средние, компактные и большие. В малой модели используется 16-разрядная адресация для любых функций или данных. Средние используемые 16-разрядные адреса для данных и 20-битные адреса для кода. Компактность инвертирована (16-разрядные адреса для кода, 20-разрядные адреса для данных). Большие используемые 20-битные адреса для кода и данных. Таким образом, в компактной или средней модели преобразование между указателями на код и указатели на функции действительно могло и могло привести к проблемам.

В последнее время большое количество DSP использовало полностью отдельные шины памяти для кода и данных и (например, с моделями памяти MS-DOS), они часто различались по ширине, конвертация между двумя могла и потеряла информацию.


  • Эти конкретные правила пришли к С++ из C, поэтому то же самое верно в C, что бы это ни стоило.
  • Хотя это не требуется напрямую, поскольку все работает, в значительной степени то же самое можно сказать о том, что для преобразования из исходного типа в указатель на char и обратно, что бы это ни стоило.

Ответ 2

Почему функция не является объектом? Как он отличается?

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

Хорошо, пусть немного продвинется по абстракциям. Я не беру на себя какие-либо абстракции, наложенные языком программирования (например, объект, массив и т.д.), Но просто как непрофессионал я хочу сохранить запись части памяти, назовем ее Ab1, а другой - Ab2.

Оба имеют состояние в основном, но я намерен манипулировать/использовать состояние по-разному.

Иными словами... Почему и как?

Почему?

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

Как?

Мне нужно некоторое управление обе части, чтобы отслеживать, какие слова выбрать из Ab1 и копировать в Ab2 и так далее. На этом этапе я понимаю, что я могу заставить его работать, чтобы выполнить некоторые простые операции, но что-то серьезное потребует выложенной спецификации для управления этой памятью.

Итак, я ищу такую ​​спецификацию управления, и оказывается, что существует множество этих спецификаций (у некоторых есть встроенная модель памяти, другие обеспечивают гибкость для управления памятью сами) с лучшим дизайном. Фактически, потому что они (даже не диктуя, как управлять памятью напрямую) успешно определили инкапсуляцию для этого долговечного хранилища и правила того, как и когда это можно создать и уничтожить.

То же самое касается Ab2, но то, как они представляют, заставляет меня чувствовать, что это сильно отличается от Ab1. И действительно, оказывается. Они используют стек для управления состоянием Ab2 и резервируют память из кучи для Ab1. Ab2 умирает через некоторое время (после завершения выполнения).

Также, как вы определяете, что делать с Ab2, выполняется через еще одну часть хранения, называемую Ab2_Code, а спецификация для Ab1 включает аналогично Ab1_Code

Я бы сказал, это фантастика! Я получаю так много удобства, что позволяет мне решать так много проблем.

Теперь я все еще смотрю с точки зрения непрофессионала, поэтому я не чувствую удивления, действительно переживая процесс размышлений, но если вы сомневаетесь в том, что сверху вниз, вещи могут быть немного сложными в перспективе. (Я подозреваю, что произошло в вашем случае)

Кстати, я забыл упомянуть, что Ab1 называется официально, а Ab2 - стекю функций, а Ab1_Code - определение класса, а Ab2_Code - код определения функции.

И именно из-за этих различий, наложенных PL, вы обнаружите, что они настолько разные. (ваш вопрос)

Примечание. Не принимайте мое представление Ab1/Object как длинную абстракцию хранения, как правило, или конкретную вещь - это было от непрофессионала. Язык программирования обеспечивает гораздо большую гибкость с точки зрения управления жизненным циклом объекта. Таким образом, объект может быть развернут как Ab1, но может быть гораздо больше.

И имеет ли это какое-либо отношение к функторам (объектам функции)?

Обратите внимание, что ответ первой части действителен для многих языков программирования в целом (включая С++), эта часть должна быть специально связана с С++ (спецификация которой вы указали). Таким образом, у вас есть указатель на функцию, вы можете также иметь указатель на объект. Его просто другая конструкция программирования, которую определяет С++. Обратите внимание, что это связано с указателем с Ab1, Ab2, чтобы манипулировать ими, а не иметь другую отчетливую абстракцию.

Вы можете прочитать об этом определении, используя здесь:

Функторы С++ и их использование

Ответ 3

Позвольте мне ответить на вопрос на более простом языке (термины).

Что содержит функция?

В основном это инструкции для чего-то. При выполнении инструкций функция может временно хранить и/или использовать некоторые данные - и может возвращать некоторые данные.

Хотя инструкции хранятся где-то - сами эти инструкции не рассматриваются как объекты.

Затем, какие объекты?

Как правило, объекты являются объектами, которые содержат данные, которые обрабатываются/изменяются/обновляются функциями (инструкциями).

Почему разница?

Поскольку компьютеры сконструированы таким образом, что инструкции не зависят от данных.

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

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

Связь между функциями и функторами

Функции - это набор инструкций; и во время их выполнения некоторые временные данные могут потребоваться для хранения. Другими словами, некоторые объекты могут быть временно созданы во время выполнения функции. Эти временные объекты являются функторами.