Причины смешивания управляемого и неуправляемого кодов. Неуправляемый или опасный?
Если управляемые расширения C++ являются такими хорошими, тогда зачем может потребоваться создавать неуправляемый код? На этот вопрос существует несколько ответов:
- Как и в других средах, где проводится автоматическая сборка мусора (таких как Smalltalk и Java), во время выполнения часто снижается производительность из-за накладных расходов на отслеживание использования объектов (отслеживание ссылок) и удаление их в нужное время.
- Еще одним нежелательным эффектом, который часто ассоциируется с автоматической сборкой мусора, является повышение объема физической памяти, требуемой для хранения объектов, которые могут быть удалены, но еще не удалены сборщиком мусора. Более агрессивные схемы сборки мусора проигрывают в производительности, а менее агрессивные – в избыточном использовании памяти. В традиционной программе C++ программист сам решает, когда именно каждый объект удаляется из динамически распределяемой области памяти. Такой подход потенциально позволяет программисту написать программу, которая одновременно выиграет и в производительности, и в использовании памяти. К сожалению, для этого требуется большой опыт программирования и большие усилия.
- У вас могут быть действующие приложения Win32, написанные на языке C++, которые вы хотите в течение некоторого периода времени преобразовать в приложения .NET. Тогда, по крайней мере в течение переходного периода, будет существовать программа, содержащая смесь управляемого и неуправляемого кода.
- Вы можете обладать реальным опытом программирования в C++ и быть знакомым с традиционным программированием неуправляемого кода. Но если вам потребовалось разработать новые приложения для платформы .NET, то в этом случае вы можете захотеть написать программу, содержащую управляемые и неуправляемые части, в качестве простейшего подхода к миру программирования .NET, вместо того, чтобы нырять с головой в чистый С# или VB.NET.
Заметим, что приведенные аргументы для внедрения неуправляемого кода имеют смысл в определенных случаях, однако они применимы не ко всем ситуациям. Например, рассмотрим пункты 1 и 2 этого списка, в которых речь идет о вопросах производительности и эффективности использования памяти. В большинстве программ эти вопросы наиболее эффективно решаются за счет оптимизации относительно небольших, но критичных фрагментов программы. Таким образом, часто имеет смысл изначально реализовать программу, используя управляемые расширения (или даже С# или VB.NET), a затем, после внимательного анализа производительности, те участки программы, которые окажутся критичными, могут быть оптимизированы с использованием неуправляемого кода на C++.
Независимо от того, приведет ли переработка критичных участков программы к неуправляемым реализациям или нет, – в любом случае у вас имеется выбор между использованием управляемого C++, С#, VB.NET и т.д. Несомненно, пункт 3 касается только тех случаев, когда модернизируются существующие программы. Пункт 4 имеет общий смысл для программистов на C++, которые на протяжении долгого времени совершенствовались в том, что они представляли себе как "наилучший" язык, и поэтому не хотят ни на минуту отрываться от C++. Если ни один из этих доводов не подходит к вашей ситуации, то вы можете реализовать весь проект с помощью управляемых расширений C++, или же выбрать для этого другой язык .NET.
Неуправляемый или опасный?
Язык Visual C++ .NET является практически единственным в среде .NET, который может генерировать неуправляемый код. Другие языки программирования .NET, такие как С# и VB.NET, способны генерировать только управляемый код. В частности, ключевое слово unsafe (ненадежный, опасный) в С# вообще не связано с генерацией управляемого или неуправляемого исполняемого кода программы. Ключевое слово unsafe (ненадежный, опасный) в С# освобождает среду .NET от автоматического управления памятью, разрешая использование указателей на объект.
Хотя Visual C++ .NET и является единственным языком .NET, который способен генерировать неуправляемый код, вполне возможно использовать и другие языки .NET для создания управляемого кода, который взаимодействует с неуправляемым кодом, независимо от того, является ли этот управляемый код безопасным или же ненадежным. Например, приложение .NET может вызвать неуправляемые методы СОМ-объектов посредством использования простых функциональных возможностей упаковщика, а неуправляемые функции, представленные традиционными динамически подключаемыми библиотеками (DLL), включая интерфейс 32-разрядных Windows-приложений (Win32 API), доступны посредством функции PInvoke (Platform Invocation Services, Службы обращения к платформе). Указанные возможности взаимодействия будут описаны далее в этой главе.
В Visual C++ .NET имеется выбор между созданием управляемого и неуправляемого кодов, однако нет выбора между созданием безопасного и ненадежного кода. Общеязыковая среда выполнения CLR предполагает, что все программы, написанные на C++, являются ненадежными. Подобно любой программе на С#, использующей ключевое слово unsafe (ненадежный, опасный), все программы на C++ не могут быть признаны безопасными, и таким образом могут быть выполнены только после аттестации.