Техническое примечание TN2185

Подсказки по C++ и приемы для Mac OS X

Ценные интересные места для программиста на C++

Введение
Выбор опций видимости
Выбор шаблона XCode
Новое/удаляющее переопределение
Сильный атрибут для пространства имен Используя объявления
Используя пространства имен для управления версиями
Какие символы C++ станд. установлены в камне, и которые не являются (проблемы ABI)
Как лучше всего разделить
Используя basic_string Инстанцирования Кроме строки и wstring С libstdc ++
Совместимость выпуска к версии выпуска совместно используемых библиотек Используя APIs C и реализации C++
Совместимость выпуска к версии выпуска совместно используемых библиотек Используя C++ APIs и реализации C++
История версии документа

Введение

Этот документ стремится упростить задачу обеспечения современного, сложного C++ Мужественные приложения к Mac OS X. Это решает несколько проблем, обычно возникающих с некоторыми полезными предложениями. В то время как ни в коем случае полная ссылка, это должно получить озадаченного разработчика C++, возглавляющего в правильном направлении, и оборудованный возможностью найти больше всесторонней информации при необходимости.

Выбор опций видимости

В видимости GCC сродни тому, что другие инструменты именуют как динамическая библиотека, import/export. Однако, символы GCC являются или видимыми или скрытыми. Видимые символы являются Вашими совместно используемыми точками входа библиотеки. Более подробная информация доступна при Управлении Видимостью Символа. Только краткий обзор предлагается здесь.

В C относительно просто решить, какие символы должны быть видимы, и который скрытый. Совместно используемые точки входа библиотеки должны быть видимы, и все остальное может быть скрыто. В C++ еще много определений найдены в заголовочных файлах вместо исходных файлов. Заголовочные файлы C++ могут содержать и интерфейсные и частные подробные данные реализации. Примеры включают шаблоны (и класс и функция), объявления класса и подставляемые функции (и участник и лицо, не являющееся членом какой-либо организации,).

Существует четыре метода для объявления видимости:

  1. Параметры командной строки (например. -fvisibility=hidden)

  2. прагмы

  3. Объявления атрибута на отдельных типах и функциях

  4. Export/unexport списки

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

Параметры командной строки для видимости

Параметры командной строки видимости полезны для установки значений по умолчанию видимости. Это может быть особенно полезно при контакте с исходным кодом, который является третьим лицом, или иначе по некоторым причинам не практичный для украшения атрибутами или прагмами. Если Вы не укажете опцию видимости командной строки тогда, то символы будут отмечены видимые (если не переопределено одним из других трех методов). Можно сделать этот выбор видимости по умолчанию, явной путем размещения следования командной строки:

 -fvisibility=default

Указание -fvisibility=hidden на метках командной строки все символы, как скрытый (если не переопределено прагмами или атрибутами - списки экспорта не могут сделать скрытый символ видимым).

Существует две других связанных с видимостью опции команды, которые можно счесть полезным:

  1. Использовать -fvisibility-inlines-hidden объявить, что не будет никакой попытки сравнить указатели на встроенные функции членства, где адреса этих двух функций членства были взяты в различных модулях связи.

    Для многих приложений, -fvisibility-inlines-hidden безопасный и простой способ скрыть много символов, который поочередно улучшает время загрузки. Динамический компоновщик (во время загрузки) действительно намного больше работает на видимые символы, чем для скрытых.

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

    • -fvisibility-inlines-hidden не имеет никакого эффекта когда -fvisibility=hidden находится также на командной строке.

    • -fvisibility-inlines-hidden не имеет никакого эффекта на подставляемые функции лица, не являющегося членом какой-либо организации.

    • Не использовать -fvisibility-inlines-hidden если Вы сравниваете указатели на встроенные функции членства через совместно используемые границы библиотеки.

  2. -fvisibility-ms-compat устанавливает видимость по умолчанию в скрытый, за исключением type_info данные связались с типами. Влияние этого должно эмулировать модель связи Microsoft Visual Studio. Сравнение типов важно для ловли исключений, dynamic_cast, и сравнение type_infoполученный a typeid выражение.

    • -fvisibility=hidden не имеет никакого эффекта когда -fvisibility-ms-compat находится также на командной строке.

    • -fvisibility-inlines-hidden не имеет никакого эффекта когда -fvisibility-ms-compat находится также на командной строке.

    • Использование -fvisibility-ms-compat может вызвать два подробных класса реализации, независимо разработанные в различных совместно используемых библиотеках, которые случайно будут приняты за тот же тип.

    • -fvisibility-ms-compat флаг скроет любые статические элементы данных типов, давая каждому модулю связи частные копии (если сказанные данные не будут иначе отмечены видимые).

Установка видимости с прагмами

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

Установить режим по умолчанию компилятора в видимый:

#pragma GCC visibility push(default)

Установить режим по умолчанию компилятора в скрытый:

 #pragma GCC visibility push(hidden)

Для отмены последней видимости GCC продвигают прагму:

 #pragma GCC visibility pop

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

Управлять видимостью метаданных компилятора для типа (например. type_info) окружите описание типа:

 #pragma GCC visibility push(default)      class MyType     {         // ...     };      #pragma GCC visibility pop

Установка видимости с атрибутами

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

Например, для маркировки функции как видимую:

 __attribute__((__visibility__("default"))) void MyFunction1() {}

И отметить функцию, как скрытый:

__attribute__((__visibility__("hidden"))) void MyFunction2() {}

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

 #define PUBLIC  __attribute__((__visibility__("default")))     #define PRIVATE __attribute__((__visibility__("hidden")))      PUBLIC  void MyFunction1() {}     PRIVATE void MyFunction2() {}

Можно отметить a class или struct как так:

 class PUBLIC MyClass {/*...*/};

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

Сокрытие символов со списками экспорта

Последний инструмент в нашем ящике для инструментов является списком экспорта. Это - просто список символов (который должен быть в искаженной форме), которые говорят компоновщику, какие символы Вы хотите скрытый. Существует две формы:

  1. Скажите компоновщику, какие символы Вы хотите сделать видимым и скрыть все остальное с -exported_symbols_list $FILENAME.

    Те символы в exported_symbols_list, должно быть, были отмечены видимые компилятором, или они будут скрыты.

  2. Скажите компоновщику который символы скрыться с -unexported_symbols_list $FILENAME.

    Те символы, отмеченные видимые компилятором и не появляющиеся в unexported_symbols_list, будут видимы.

Подведение видимости символа итогов

Может быть удобно полагаться на комбинацию вышеупомянутых инструментов видимости. Например, если Ваша библиотека имеет много символов, которые должны быть скрыты, с только некоторыми, которые должны быть видимы, можно хотеть использовать -fvisibility=hidden и только украсьте исходный код тех немногих символов, которые должны быть видимы.

Для тех типов, которые Вы ожидаете throw или dynamic_cast через совместно используемую границу библиотеки эти типы должны быть отмечены как видимые одним из вышеупомянутых методов. Отказ сделать так приведет к ошибкам периода выполнения, таким как a catch пункт, пропускающий вызванную исключительную ситуацию. Например.:

 // MyException.h

    class MyException {};

    // shared library:

    #include "MyException.h"

    void my_func()
    {
        throw MyException();
    }

    // Application:

    #include "MyException.h"

    int main()
    {
        try
        {
            my_func();
        }
        catch (MyException&)
        {
            // Catch will miss if MyException is hidden
            // If hidden, the MyException thrown is a different type, than
            //    the MyException referred to in the catch clause.
        }
    }

Выбор шаблона XCode

При выборе «New Project...» в XCode существует большое разнообразие шаблонов XCode для выбора из. Для разработчика C++, с какого шаблона необходимо запустить? Можно было запустить с любого из шаблонов и установить все самостоятельно. Однако при выборе самого соответствующего шаблона с начала настройки по умолчанию, более вероятно, сделают то, что Вы хотите.

Существует шесть шаблонов XCode, особенно адаптированных для разработчика C++, распространенного всюду по четырем типам приложения:

Шаблоны приложений

Выберите один из Шаблонов приложений Углерода для создания приложения C++ начинающего на основе Углерода API. Приложение-стартер выведет на экран окно приложения OS X, реагирующее на обычные команды работы с окнами (новый, близко, минимизируйте, и т.д.). В этом шаблоне существует также окно «About» в качестве примера. Шаблон также демонстрирует в стиле C++, как можно поймать и настроить события и читать из файлов пера.

Единственной разницей между «Приложением C++ Углерода» и «Приложением Стандарта C++ Углерода» является установка видимости по умолчанию. Значения по умолчанию шаблона «Standard» к видимому, в то время как другие шаблонные значения по умолчанию к скрытому. При выборе скрытых значений по умолчанию видимости нужно заботиться при соединении с совместно используемыми библиотеками, что те символы, которые должны быть известны через совместно используемую библиотеку, явно объявляются видимые при помощи художественных оформлений атрибута или прагм. Это включает type_info данные, использующиеся в реализации try/catch и dynamic_cast. Минимизация видимых символов делает устойчивость ABI среди модулей связи более простой, и также минимизирует время загрузки. С шаблоном «Standard» все эти функции языка C++ работают как ожидалось без дальнейшего усилия со стороны разработчика.

Универсальный плагин C++

Этот проект создает универсальный шаблон C++, представляющий интерфейс C, пользующийся статической библиотекой стандарта C++ и использующий Карлика для отладки.

Этот шаблон создает демонстрационный «плагин» или пакет. Это - совместно используемая библиотека, которая может быть загружена и разгружена динамично всюду по времени жизни приложения. Плагин в качестве примера, проектом, экспортирует только интерфейс C и не выдает исключений. Однако, это реализовано внутренне с C++. Это скрыло видимость по умолчанию и соединяется статически с libstdc ++. Это позволяет ему бросить и поймать исключения внутренне, но сохранить свои клиенты в блаженном неведении о том факте.

Шаблон демонстрирует использование прагм для маркировки его видимого интерфейса C. Это также демонстрирует «частные заголовки», содержащие объявления C++, предназначающиеся, чтобы использоваться внутренне только (и отмечены со скрытой видимостью).

Инструмент командной строки C++

Если требуется записать простой HelloWorld или программу, не имеющую никакого графического интерфейса пользователя (ограниченный стандартной консолью C++ и файловым вводом-выводом), то это - шаблон для запуска с. Это начинает Вас с единственным main.cpp, только распечатывающим «Привет, Мир! \n». Когда создано и запущено от XCode, консольный вывод видим в Журнале Выполнения XCode. Это приложение может также быть запущено от Terminal.app.

Этому установили видимость в скрытый по умолчанию. Если Вы предпочли бы видимый для значения по умолчанию, выберите «Edit Active Target» под Меню проектов, введите «vis» в поле поиска диалогового окна, подходящего, и снимите флажок «С символами, Скрытыми» и «Скрытыми Подставляемыми функциями по умолчанию».

Динамическая библиотека

Эти шаблоны устанавливают пример динамическая (совместно используемая) библиотека. Пример включает и общедоступный (видимый) интерфейс и частные (скрытые) внутренние заголовки. Как шаблоны приложений, значения по умолчанию шаблона «Standard» ко всему видимому, в то время как шаблон без слова «Standard» в значениях по умолчанию имени к скрытой видимости.

Новое/удаляющее переопределение

Стандарт C++ (ISO № 14882-2003) говорит, что следующие 8 подписей могут быть заменены клиентским кодом:

 void* operator new(std::size_t size) throw(std::bad_alloc);
    void* operator new(std::size_t size, const std::nothrow_t&) throw();
    void  operator delete(void* ptr) throw(); 
    void  operator delete(void* ptr, const std::nothrow_t&) throw();

    void* operator new[](std::size_t size) throw(std::bad_alloc);
    void* operator new[](std::size_t size, const std::nothrow_t&) throw();
    void  operator delete[](void* ptr) throw();
    void  operator delete[](void* ptr, const std::nothrow_t&) throw();

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

Ваши замены будут иметь силу широкое приложение. Даже код в других модулях связи (совместно использованные библиотеки) вызовет Ваше пользовательское new и delete. Всюду по приложению (все модули связи), должно быть только одно определение для замененного new и delete. Это гарантирует, что, если владение памяти передается через совместно используемую границу библиотеки, оно будет удалено правильно.

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

При редких обстоятельствах совместно используемая библиотека может счесть удобным иметь частные определения этих операторов. Это сделано путем соединения с -unexported_symbols_list флаг имени файла и размещение следующих символов в unexport file:

 __Znwm
    __Znwm.eh
    __ZnwmRKSt9nothrow_t
    __ZnwmRKSt9nothrow_t.eh
    __ZdlPv
    __ZdlPv.eh
    __ZdlPvRKSt9nothrow_t
    __ZdlPvRKSt9nothrow_t.eh

    __Znam
    __Znam.eh
    __ZnamRKSt9nothrow_t
    __ZnamRKSt9nothrow_t.eh
    __ZdaPv
    __ZdaPv.eh
    __ZdaPvRKSt9nothrow_t
    __ZdaPvRKSt9nothrow_t.eh

При этом автор должен гарантировать, что владение памяти не передается в, или из, эта совместно используемая библиотека. Обратите внимание на то, что передача владения памяти может произойти тонкими способами, такими как передающая ссылка считаемые объекты (например. std::string), выдача исключений, содержащих «кучу», выделила сообщение (например. std::runtime_error) или встраивание выделяющего ресурс конструктора, с соответствующим деструктором, не встроенным (или наоборот).

Наш текущий комплект инструментальных средств имеет ошибку посредством чего, если единица перевода заменит этих операторов и не будет содержать символ со слабой связью (например, подставляемая функция или неявное шаблонное инстанцирование), то компоновщик не найдет пользовательский оператор new/delete. Большинство реальных единиц перевода будет иметь слабые символы, таким образом, это обычно будет не проблемой. Однако, должны Вы быть затронутыми этой ошибкой, можно добавить следующую строку рядом с определениями оператора:

 __attribute__((__weak__, __visibility__("default"))) int dummy_weak_symbol_for_new;

Сильный атрибут для пространства имен Используя объявления

Рассмотрите следующий код:

 namespace Acme
    {

    template <class T>
    class V
    {
    };

    template <class T>
    void func1(T&) {}

    template <class T>
    void func2(T&) {}

    } // Acme

    // Acme client

    struct MyType {};

    namespace Acme
    {

    template <>
    class V<MyType>
    {
    };

    }  // Acme

    int main()
    {
        Acme::V<int> v_int;
        func1(v_int);
        Acme::func2(v_int);
        Acme::V<MyType> v_mytype;
        func1(v_mytype);
        Acme::func2(v_mytype);
    }

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

Теперь полагайте, что по некоторым причинам, Высшая точка хочет поместить часть своей функциональности во вложенном пространстве имен Высшей точки, и затем импортировать ее в пространство имен Высшей точки с объявлением использования. Намерение состоит в том, чтобы изменить ABI библиотеки с сохранением контроля над ситуацией при содержании стабильного API (т.е. код, перекомпилированный против новой библиотеки, не должен изменяться, но получает новое искажение). Почему они могли бы хотеть сделать, это покрыто позже:

// Acme library

namespace Acme
{

namespace _1
{

template <class T>
class V
{
};

template <class T>
void func1(T&) {}

}  // _1

using namespace _1;

template <class T>
void func2(T&) {}


} // Acme

Это работает на большинство клиентов, поскольку они могут быть блаженно неосведомлены о вложенном пространстве имен и продолжать просто использовать Acme::V и Acme::func1. Но это повреждает клиентский код, который мы показали ранее.

error: specialization of 'template<class T> class Acme::_1::V' in different namespace

Т.е. клиент больше не может специализироваться Acme::V<T>. Они должны вместо этого специализироваться Acme::_1::V<T>, который неудачен, потому что мы хотели сделать вложенное пространство имен прозрачным на уровне API. Однако, внесение этого изменения все еще не фиксирует все:

error: 'func2' was not declared in this scope

Эта ошибка относится к обоим из использования func2 в коде клиента:

func2(v_int); func2(v_mytype);

С тех пор V теперь жизни в Acme::_1, пространство имен Acme не разыскивается func2.

Компилятор GCC имеет расширение, чтобы заставить этот код работать, и без клиента, имеющего необходимость знать о вложенном пространстве имен:

 using namespace _1 __attribute__((__strong__));

Теперь исходный код клиента, даже специализация Acme::V<T>, просто работы. И все же, V и func1 теперь искажаются с вложенным пространством имен Acme::_1.

Почему Высшая точка преднамеренно ввела бы эту потенциально запутывающую ситуацию в их API?

Используя пространства имен для управления версиями

Если бы Вы не считали раздел по Сильному Атрибуту для Пространства имен Используя Объявления, теперь было бы хорошее время, чтобы сделать так. Если Вы только что произошли из того раздела, этот раздел об ответе на тот заключительный вопрос: Почему?

Поскольку можно собрать из заголовка этого раздела, можно использовать метод, описанный в предыдущем разделе для управления версиями ABI библиотеки, не изменяя API библиотеки (или по крайней мере содержа изменения API в назад совместимых). В контексте совместно используемых библиотек это означает, что можно одновременно поставить многократные версии совместно используемой библиотеки, и отдельное приложение может косвенно соединиться с многократными версиями без страха перед тихими ошибками периода выполнения вследствие смешиваемых несовместимых версий.

Рассмотрите следующее:

Высшая точка совместно использовала версии 1 и 2 библиотеки, которые они поставляют: высшая точка 1.dylib и Высшая точка 2.dylib. Другие совместно используемые библиотеки (Lib_A и Lib_B) соединяются с Высшей точкой для их ценных служб. Lib_B перекомпилировал против Высшей точки 2.dylib, но Lib_A все еще использует Высшую точку 1.dylib. Наконец, ссылки на приложение и на Lib_A и на Lib_B, эффективно смешивая обе версии Высшей точки в тот же процесс.

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

Управление версиями с пространствами имен адресует вышеупомянутый сценарий. Поскольку пространства имен искажаются на имена символов, скрытые пространства имен в Высшей точке пространства имен искажаются в func1. На уровне объектного кода, двух различных версиях func1 буквально две отличных функции, с двумя отличными именами. Все же на уровне исходного кода, обе версии, кажется, имеют имя Acme::func1. Главное приложение может вызвать func1 без проблем. Если это сделало заголовки версии 1 настолько использующей Высшей точки, это доберется Acme::_1::func1. Если это использовало заголовки версии 2 Высшей точки, это доберется Acme::_2::func1. Если это использовало заголовки версии 1, но больше не соединяется (прямо или косвенно) против Высшей точки 1.dylib, это получит ссылку или отказ времени загрузки как Acme::_1::func1 не будет найден, даже если Acme::_2::func1 был загружен в процесс.

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

Какие символы C++ станд. установлены в камне, и которые не являются (проблемы ABI)

Если Вы считали Сильный Атрибут для Пространства имен Используя Объявления, и Используя Пространства имен для Управления Версиями тогда Вы, возможно, уже предположили, что это - план Apple относительно библиотеки стандарта C++. Со временем, и несовместимые с ABI изменения внесены в нашу библиотеку стандарта C++, мы присвоим версию им, как описано выше так, чтобы мы могли одновременно предложить более старые, совместимые версии ABI и более новые, несовместимые версии ABI стандартной библиотеки. Клиенты будут в состоянии выбрать версии на основе своих индивидуальных потребностей, и если приложение, оказывается, загружается, третье лицо совместно использовало библиотеки, не будет никакой опасности тихого смешивания несовместимого std:: компоненты.

Вы, возможно, также заметили, что в нашем примере Высшей точки выше, был один символ (func2)) оставленный за пределами вложенного пространства имен управления версиями. В этом примере, func2 представляет символ, какая Высшая точка гарантирует, что была стабильна ABI, даже через версии.

Аналогично, Apple гарантирует, что маленькое подмножество библиотеки стандарта C++ не изменит ABI, даже через новые версии этой библиотеки. То подмножество стабильных ABI подписей:

 namespace std {

    // rtti

    class type_info;

    // exceptions

    class exception;
    class bad_exception;
    class bad_cast;
    class bad_typeid;
    class bad_alloc;
    class logic_error;
    class domain_error;
    class invalid_argument;
    class length_error;
    class out_of_range;
    class runtime_error;
    class range_error;
    class overflow_error;
    class underflow_error;

    // handlers

    unexpected_handler set_unexpected(unexpected_handler) throw();
    void unexpected();
    terminate_handler set_terminate(terminate_handler) throw();
    void terminate();
    uncaught_exception() throw();
    struct nothrow_t {};
    new_handler set_new_handler(new_handler) throw();

    }  // std

    // new / delete

    void* operator new(std::size_t) throw(std::bad_alloc);
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void  operator delete(void*) throw();
    void  operator delete(void*, const std::nothrow_t&) throw();
    void* operator new[](std::size_t) throw(std::bad_alloc);
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void  operator delete[](void*) throw();
    void  operator delete[](void*, const std::nothrow_t&) throw();
    void* operator new (std::size_t, void*) throw();
    void* operator new[](std::size_t, void*) throw();
    void  operator delete (void*, void*) throw();
    void  operator delete[](void*, void*) throw();

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

Как лучше всего разделить

Соединенный Мужественный двоичный файл содержит два вида символов: глобальная переменная и локальный. Глобальные символы используются dyld чтобы сделать привязку и доступны для поиска при использовании во время выполнения dlsym(). Локальные символы используются отладчиками и CrashReporter при представлении символьных имен для адресов. Все конструкции C++ со скрытой видимостью становятся локальными символами, когда соединено.

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

Самому быстрому способу удалить локальные символы состоял в том, чтобы поместить компоновщика никогда их в выходном двоичном файле. Опция компоновщика -x сделает это. Если Вы хотите иметь два двоичных файла один с и один без локальных символов, Вы можете сделать, чтобы компоновщик генерировал локальные символы, сделал из копии программы и использовал strip инструмент с -x опция удалить локальные символы из копии.

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

Используя basic_string Инстанцирования Кроме строки и wstring С libstdc ++

При использовании std::basic_stringкроме string и wstring, объединенный со скрытой видимостью, необходимо включать string заголовок перенесся в #pragma GCC visibility push(default). Отказ сделать так может привести к двойному, удаляют связанный с пустой строкой. Это считают ошибкой Apple (r. 4940079), и будет исправлен в будущем выпуске.

Пример:

 $ cat library.h

        #ifndef LIBRARY_H
        #define LIBRARY_H

        #include <string>

        typedef unsigned short uchar;
        typedef std::basic_string<uchar> ustring;

        __attribute__ ((visibility("default"))) ustring foo();

        #endif  // LIBRARY_H

    $ cat library.cpp

        #include "library.h"

        ustring foo()
        {
            ustring s;
            return s;
        }

    $ cat main.cpp

        #include "library.h"

        int main()
        {
            ustring s;
            s = foo();
        }

    $ export MallocBadFreeAbort=1
    $ g++ -fvisibility=hidden -dynamiclib -o library.so library.cpp
    $ g++ -fvisibility=hidden -o main main.cpp library.so
    $ ./main

        main(5585) malloc: ***  Deallocation of a pointer not malloced: 0xc0ac; This
        could be a double free(), or free() called with the middle of an allocated
        block; Try setting environment variable MallocHelp to see tools to help debug
        Abort trap

Для фиксации измениться <library.h> к:

 $ cat library.h

        #ifndef LIBRARY_H
        #define LIBRARY_H

        #pragma GCC visibility push(default) //added change
        #include <string>
        #pragma GCC visibility pop                 //added change

        typedef unsigned short uchar;
        typedef std::basic_string<uchar> ustring;

        __attribute__ ((visibility("default"))) ustring foo();

        #endif  // LIBRARY_H

Совместимость выпуска к версии выпуска совместно используемых библиотек Используя APIs C и реализации C++

Можно поддержать чистый интерфейс C к совместно используемой библиотеке при использовании в своих интересах C++ в реализации совместно используемой библиотеки.

Для получения дополнительной информации и хорошие предложения видят справочную документацию Apple на динамическом руководстве по проектированию библиотеки.

Совместимость выпуска к версии выпуска совместно используемых библиотек Используя C++ APIs и реализации C++

Можно также иметь интерфейс C++ к совместно используемой библиотеке. В дополнение к следующему точки перечислили в предыдущем разделе, нужно также полагать, что следующий помогает поддержать стабильный ABI:



История версии документа


ДатаПримечания
25.05.2007

Исправление раздела по установке функциональной видимости через атрибуты: #define PUBLIC __ атрибут __ ((__ видимость __ («скрытый»))) #define PRIVATE __ атрибут __ ((__ видимость __ («значение по умолчанию»))) PUBLIC недействительный MyFunction1 () {} PRIVATE недействительный MyFunction2 () {} имел PUBLIC и макросы PRIVATE, определенные назад.

25.01.2007

Новый документ, что подсказки и приемы для как начинающих, так и опытных программистов на C++ на Mac OS X.