Основы указателей
Основы указателей
СОМ, подобно DCE (Distributed Computing Environment – среда распределенных вычислений), ведет свое начало от языка программирования С. Хотя лишь немногие разработчики используют С для создания или использования компонентов СОМ, именно от С СОМ унаследовала синтаксис для своего языка определений интерфейсов (Interface Definition Language – IDL). Одной из наиболее сложных проблем при разработке и использовании интерфейсов является управление указателями. Рассмотрим такое простое определение метода IDL:
HRESULT f([in] const short *ps);
Если бы вызывающая программа должна была запустить этот метод так:
short s = 10;
HRESULT hr = p->f(&s);
то величину 10 следовало бы послать объекту. Если бы этому методу нужно было выйти за границы апартамента, то интерфейсный заместитель был бы обязан разыменовать указатель и передать величину 10 в сообщение ORPC-запроса.
Следующий клиентский код, хотя и написан целиком в традициях С, представляет собой более интересный случай:
HRESULT hr = p->f(0);
// pass a null pointer
// передаем нулевой указатель
Если вызывающий поток выполняется в апартаменте объекта, то заместителя нет и нулевой указатель будет передан прямо объекту. Но что если объект расположен в другом апартаменте и заместитель используется? Что в точности должен передать интерфейсный заместитель, чтобы показать, что был послан нулевой указатель? Кроме того, означает ли это, что интерфейсные заместители и заглушки должны проверять каждый указатель, не является ли он нулевым? Оказывается, бывают ситуации, в которых указатель никогда не должен быть нулевым, и другие ситуации, когда нулевые указатели, наоборот, чрезвычайно полезны как начальные значения. В последнем случае факт передачи нулевого указателя интерфейсному заместителю должен быть продублирован интерфейсной заглушкой в апартаменте объекта.
Для того чтобы удовлетворить этим столь различным требованиям, СОМ позволяет разработчикам интерфейсов указывать точную семантику каждого параметра указателя. Чтобы показать, что указатель никогда не должен принимать нулевого значения, разработчик интерфейса может применить атрибут [ref]:
HRESULT g([in, ref] short *ps);
// ps cannot be a null ptr.
// ps не может быть нулевым указателем
Указатели, использующие атрибут [ref], называются ссылочными указателями (reference pointers). При IDL-определении, приведенном выше, следующий код со стороны клиента:
HRESULT hr = p->g(0);
// danger: passing null [ref] ptr.
// опасность: передается нулевой указатель с атрибутом [ref]
является ошибочным. И если p указывает на интерфейсный заместитель, то данный интерфейсный заместитель обнаружит нулевой указатель и возвратит вызывающей программе ошибку маршалинга, даже не передав метод текущему объекту. А чтобы сделать нулевой указатель допустимым значением параметра, в IDL-определении следует использовать атрибут [unique]:
HRESULT h([in, unique] short *ps);
// ps can be a null ptr.
// ps может быть нулевым указателем
Указатели, использующие атрибут [unique], называются уникальными указателями (unique pointers). При IDL-определении, приведенном выше, следующий код со стороны клиента:
HRESULT hr = p->h(0);
// relax: passing null [unique] ptr.
// расслабьтесь: передается нулевой указатель с атрибутом [unique]
является допустимым. Это означает, что интерфейсный заместитель должен подробно исследовать указатель перед тем, как разыменовать его. И что более важно: это означает, что интерфейсному заместителю необходимо записывать в ответ на ORPC-запрос не только разыменованную величину. Кроме нее, он должен записать тег, указывающий, был или не был передан нулевой указатель. Это добавляет к размеру ORPC-сообщения четыре байта на каждый указатель. Для большинства приложений эти добавочные четыре байта и то процессорное время, которое необходимо для выявления нулевого указателя[1], пренебрежимо малы по сравнению с преимуществами использования нулевых указателей в качестве параметров.
Вообще говоря, схемы [ref] и [unique] мало отличаются по эффективности. Однако до сих пор не обсуждалась еще одна проблема, связанная с указателями. Рассмотрим следующий фрагмент на IDL:
HRESULT j([in] short *ps1, [in] short *ps2);
Имея такое IDL-определение, рассмотрим теперь следующий фрагмент кода со стороны клиента:
short x = 100;
HRESULT hr = p->j(&x, &х);
// note: same ptr. passed twice
// заметим: тот же самый указатель передан дважды
Естественный вопрос: что должен делать интерфейсный заместитель при наличии одинаковых указателей? Если интерфейсный заместитель не делает ничего, тогда значение 100 будет передано в ORPC-запросе дважды: один раз для *ps1 и один раз для *ps2. Это означает, что заместитель посылает одну и ту же информацию дважды, впустую занимая сеть и тем самым уменьшая ее пропускную способность. Конечно, число байтов, занятых величиной 100, невелико, но если бы ps1 и ps2 указывали на очень большие структуры данных, то повторная передача существенно повлияла бы на производительность. Другой побочный эффект от невыявления дублирующего указателя состоит в том, что интерфейсная заглушка будет демаршалировать эти значения в два различных места памяти. Если бы семантика метода изменилась из-за тождественности двух таких указателей:
STDMETHODIMP MyClass::j(short *ps1, short *ps2)
{
if (ps1 == ps2)
return this->OneKindOfBehavior(ps1);
else
return this->AnotherKindOfBehavior(ps1, ps2);
}
то интерфейсный маршалер нарушил бы семантический контракт (semantic contract) интерфейса, что нарушило бы прозрачность экспорта в СОМ.
Наличие атрибутов указателя [ref] и [unique] означает, что память, на которую ссылается указатель, не является ссылкой для какого-либо другого указателя в вызове метода и что интерфейсный маршалер не должен осуществлять проверку на дублирование указателей. Для того чтобы показать, что указатель может ссылаться на память, на которую ссылается другой указатель, разработчику IDL следует использовать атрибут [ptr]:
HRESULT k([in, ptr] short *ps1, [in, ptr] short *ps2);
Указатели, использующие атрибут [ptr], называются полными указателями (full pointers), потому что они наиболее близки к полному соответствию с семантикой языка программирования С. Имея такое IDL-определение, следующий код со стороны клиента:
short x = 100;
HRESULT hr = p->k(&x, &x);
// note: same ptr. passed twice
// заметим: тот же самый указатель передан дважды
передаст значение 100 ровно один раз, поскольку атрибут [ptr] при параметре ps1 сообщает интерфейсному маршалеру, что следует выполнить проверку на дублирование для всех остальных указателей с атрибутом [ptr]. Поскольку параметр ps2 также использует атрибут [ptr], интерфейсный маршалер определит значение дублирующего указателя[2], а разыменует и передает значение только одного из указателей. Интерфейсная заглушка отметит, что это значение должно быть передано с обоими параметрами, ps1 и ps2, вследствие чего метод получит один и тот же указатель в обоих параметрах.
Хотя полные указатели могут решать различные проблемы и в определенных случаях полезны, они не являются предпочтительными указателями в семантике СОМ. Дело в том, что в большинстве случаев разработчик знает заранее, что дублирующие указатели передаваться не будут. Кроме того, поскольку полные указатели обеспечивают более короткие ORPC-сообщения в случае, если они являются дублирующими указателями, то расход ресурсов процессора на поиск дублирующих указателей может стать нетривиальным с ростом числа указателей на каждый метод. Если разработчик интерфейса уверен, что никакого дублирования не будет, то разумнее учесть это и использовать либо уникальные, либо ссылочные указатели.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Разрешение системных указателей
Разрешение системных указателей Системный указатель считается разрешенным, если содержит прямой адрес системного объекта. Указатель, содержащий символический адрес, называется неразрешенным. Символический адрес используется для поиска объекта в библиотеке и состоит
Другие типы указателей
Другие типы указателей Системный указатель обеспечивает доступ к системному объекту, но при выполнении некоторых операций нужно работать с данными, содержащимися внутри таких объектов. Для этого используются другие типы указателей. Но прежде чем рассказать о них, я
Аппаратная защита указателей
Аппаратная защита указателей Мы понимали, что необходима некоторая форма аппаратной защиты памяти для указателей. Многие из больших систем того времени, такие как System/370, использовали для защиты памяти специальные аппаратные разряды, разрешавшие или запрещавшие
Выбор указателей мыши
Выбор указателей мыши Еще одной отличительной особенностью интерфейса Windows Vista стал набор изящных видов указателей мыши. Как и в предыдущих версиях Windows, у вас сохранилась возможность изменять вид указателя при различных состояниях. В окне Персонализация щелкните
7.7. Изменение указателей мыши
7.7. Изменение указателей мыши Возможность настройки указателей мыши существовала и в самых ранних версиях операционной системы Windows, поэтому разработчики Windows 7 решили не изобретать велосипед и использовать уже отлаженный механизм. При этом они взяли его в том виде, в
Проблема обобщенных указателей
Проблема обобщенных указателей Что такое обобщенные указатели и почему они полезны Представим себе некий объект, который имеет перегруженную операцию operator->(). Мы можем его представить себе как некий обобщенный указатель, который не является указателем в полном смысле
Выбор указателей мыши
Выбор указателей мыши Указатели мыши в Vista выглядят изящно, но не совсем привычно. Если хотите, можете поменять и их. Для этого щелкните кнопкой мыши на ссылке Указатели мыши в окне Персонализация. В открывшемся окне вы увидите примеры указателей для выбранной схемы (рис.
R.4.6 Преобразования указателей
R.4.6 Преобразования указателей Всюду, где указатели (§R.8.2.1) присваиваются, инициализируются, сравниваются или используются иным образом, могут происходить следующие преобразования:Константное выражение (§R.5.19), которое сводится к нулю, преобразуется в указатель, обычно
6.4. Хранение указателей в векторе
6.4. Хранение указателей в векторе ПроблемаС целью повышения эффективности или по другим причинам невозможно хранить копии объектов в vector, но их требуется как-то разместить.РешениеСохраните в vector указатели на объекты, а не копии самих объектов. Но при этом не забудьте
Совет 7. При использовании контейнеров указателей, для которых вызывался оператор new, не забудьте вызвать delete для указателей перед уничтожением контейнера
Совет 7. При использовании контейнеров указателей, для которых вызывался оператор new, не забудьте вызвать delete для указателей перед уничтожением контейнера Контейнеры STL отличаются умом и сообразительностью. Они поддерживают итераторы для перебора как в прямом, так и в
Описание указателей
Описание указателей Мы знаем, как описывать переменные типа int и других типов. Но как описать переменную типа "указатель"? На первый взгляд это можно сделать так: pointer ptr; /* неправильный способ описания указателя */Почему нельзя использовать такую запись? Потому
3.9.2. Взаимосвязь массивов и указателей
3.9.2. Взаимосвязь массивов и указателей Если мы имеем определение массива:int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 };то что означает простое указание его имени в программе?ia;Использование идентификатора массива в программе эквивалентно указанию адреса его первого элемента:ia;ia[0]Аналогично
7.9.4. Массивы указателей на функции
7.9.4. Массивы указателей на функции Можно объявить массив указателей на функции. Например:int (*testCases[10])();testCases – это массив из десяти элементов, каждый из которых является указателем на функцию, возвращающую значение типа int и не имеющую параметров.Подобные объявления
6.7 Преобразования Указателей
6.7 Преобразования Указателей Везде, где указатели присваиваются, инициализируются, сравниваются и т.д. могут выполняться следующие преобразовния.Константа 0 может преобразовываться в указатель, и грантируется, что это значение породит указатель, отлиный от указателя на
Типы указателей
Типы указателей PBoolean Тип указателя на boolean PByte Тип указателя на byte PShortint Тип указателя на shortint PChar Тип указателя на char PSmallint Тип указателя на smallint PWord Тип указателя на word PPointer Тип указателя на pointer PInteger Тип указателя на
Настройка указателей мыши
Настройка указателей мыши Для изменения формы указателей мыши щелкните кнопкой мыши в окне Персонализация на ссылке Указатели мыши. При этом откроется вкладка Указатели диалогового окна Свойства: Мышь (рис. 2.25). Рис. 2.25. Окно настройки указателей мышиВы можете выбрать