Как точно делает __, приписывают __ ((конструктор)) работа?

Кажется довольно ясным, что это, как предполагается, настраивает вещи.

  1. Когда точно это работает?
  2. Почему там две круглых скобки?
  3. __attribute__ функция? Макрос? Синтаксис?
  4. Это работает в C? C++?
  5. Функция это работает с потребностью быть статичным?
  6. Когда делает __attribute__((destructor)) выполненный?

Пример в Objective C:

__attribute__((constructor))
static void initialize_navigationBarImages() {
  navigationBarImages = [[NSMutableDictionary alloc] init];
}

__attribute__((destructor))
static void destroy_navigationBarImages() {
  [navigationBarImages release];
}

327
задан Cœur 3 March 2019 в 18:06
поделиться

1 ответ

Существует два способа реализации службы отображения, подобных описанному вами.

  1. Клиенты отправляют глобально уникальные идентификаторы, или
  2. Сервер генерирует глобально уникальные идентификаторы

Клиенты отправляют глобально уникальные идентификаторы

Насколько мне известно, 1. следует пытаться только с помощью Guid , если только вы не разработаете аналогичное средство для передачи достаточно четкой информации в короткий поток байтов. В любом случае, если у вас есть поток байтов, которые представляют глобально уникальный идентификатор, вы можете сделать что-то подобное

// source is either a Guid, or some other globally unique byte stream
byte[] bytes = Guid.NewGuid ().ToByteArray ();
string base64String = Convert.ToBase64String (bytes).Trim ("=");

, чтобы получить считываемую пользователем последовательность алфавитно-цифровых чисел, которая выглядит случайной, но избегает конфликтов, присущих другим случайным схемам. Guid содержит 16 байт или 128 бит, что соответствует приблизительно 19 символам для полной кодировки Base64.

Преимущество этого подхода в том, что клиенты могут генерировать свои собственные крошечные Uris без центрального органа. Минусом является большая длина, если вы катитесь с Guid или реализуете свой собственный глобально уникальный поток байтов, который - давайте посмотрим правде в глаза - склонен к ошибкам.

Если вы действительно идете по этому маршруту, рассмотрите глобально уникальные потоки байтов Google или такие. О, и ДЕРЖИТЕСЬ ПОДАЛЬШЕ ОТ СЛУЧАЙНЫХ БАЙТОВ , иначе вам придется построить разрешение коллизий ПОВЕРХ вашего крошечного генератора URI.

Сервер генерирует глобальные уникальные идентификаторы

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

Таким образом, если не считать серверно-ориентированного подхода, в котором единый орган власти генерирует и выдает идентификаторы, может быть более привлекательным. Если это выбранный маршрут, то вопрос только в том, как долго вы хотите ваш URI?

Предполагая желаемую длину 5 символов, и допустим, вы идете с Base64 кодировкой, каждый идентификатор может представлять до 5 символов на 7 бит на символ равно 35 бит или 2 ^ 35 [34 359 738 368] различных значений. Это довольно большой домен. *

Тогда возникает вопрос о возврате значения для данного представления. Вероятно, есть много способов сделать это, но я бы пошел с чем-то вроде этого,

  • Перечислить все возможные значения в «список свободных элементов» в базе данных
  • Удалить значение из списка свободных элементов при использовании
  • Добавить значение в список свободных элементов при выпуске

Усовершенствования или оптимизации могут включать

  • Не перечислять все значения в диапазоне [0, 2 ^ 35], вместо перечисления управляемого подмножества, скажем, 100 000 значений одновременно, и когда все значения будут израсходованы, просто создайте еще 100 000 значений в последовательности и продолжите
  • Добавьте дату истечения срока к значениям, и повторно использовать просроченные значения в конце дня
  • Распределите ваш сервис, когда параллелизация вашего сервиса просто распределяет небольшие взаимоисключающие подмножества вашего списка бесплатных услуг

Вывод

Итог:вы хотите гарантировать уникальность - так что коллизии являются большим нет-нет.


* = 34 359 738 368 - размер необработанного домена, это все идентификаторы от 0 длины до 5 длины. Если вы заинтересованы в ограничении всех идентификаторов минимальной и максимальной длиной 5, то ваш домен выглядит так, что все идентификаторы длиной от 0 до 5 (2 ^ 35) меньше, чем все идентификаторы длиной от 0 до 4 (2 ^ 28) составляет от 2 ^ 35 до 2 ^ 28 = 34 091 302 912, что все еще довольно велико:)

-121--432â6-

Вы говорите:

Для другого можно вернуть списки из функций, даже если вы никогда передан в списке при вызове функция и даже несмотря на то, что функция не содержит конструктор List, Например,

x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'

И я полагаю, вы предполагаете, что это проблема (?). Я здесь, чтобы сказать вам, почему это не проблема: -). Ваш пример немного прост, так как при разделении строки имеется список с элементами длиной 1 элемента, поэтому известно, что x [[1]] совпадает с unlist (x) [1] . Но что, если результат strsplit вернул результаты различной длины в каждой ячейке. Просто вернуть вектор (против списка) совсем не получится.

Например:

stuff <- c("You, me, and dupree",  "You me, and dupree",
           "He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))

В первом случае ( x : который возвращает список) можно указать, какой была 2-я «часть» 3-й строки, например x [[3]] [2] . Как вы могли бы сделать то же самое с помощью xx теперь, когда результаты были «распутаны» ( unlist -ed)?

-121--54025-
  1. Она запускается при загрузке общей библиотеки, как правило, во время запуска программы.
  2. Вот как все атрибуты GCC; предположительно для их отличия от вызовов функций.
  3. Синтаксис, специфичный для GCC.
  4. Да, это работает в C и C++.
  5. Нет, функция не должна быть статичной.
  6. Деструктор запускается при выгрузке общей библиотеки, обычно при выходе из программы.

Итак, работа конструкторов и деструкторов заключается в том, что файл общих объектов содержит специальные разделы (.ctors и .dtors в ELF), которые содержат ссылки на функции, отмеченные атрибутами конструктора и деструктора соответственно. Когда библиотека загружается/выгружается, программа динамического загрузчика (ld.so или somesuch) проверяет, существуют ли такие разделы, и, если да, вызывает функции, на которые в них ссылаются.

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

265
ответ дан 23 November 2019 в 00:50
поделиться