Сделать иерархию позиций в массиве

still alloca use не рекомендуется, почему?

Я не воспринимаю такой консенсус. Множество сильных профи; несколько минусов:

  • C99 предоставляет массивы переменной длины, которые часто использовались бы предпочтительнее, поскольку нотация более совместима с массивами с фиксированной длиной и интуитивным общим
  • , что многие системы имеют меньше общая память / адресное пространство, доступное для стека, чем для кучи, что делает программу немного более восприимчивой к исчерпанию памяти (через переполнение стека): это можно рассматривать как хорошее или плохое - одна из причин стек автоматически не развивается так, как это делает куча, чтобы предотвратить недоступность программ контроля недействительности для всего компьютера
  • при использовании в более локальной области (например, while или for) или в нескольких областях, память накапливается на каждую итерацию / область действия и не освобождается до выхода функции: это контрастирует с нормальными переменными, определенными в области структуры управления (например, for {int i = 0; i < 2; ++i) { X } будет накапливаться alloca запрошенную в X, но память для массива фиксированного размера будет переработана на итерацию).
  • современные компиляторы обычно не выполняют функции inline, которые вызывают alloca, но если вы их заставляете, то alloca произойдет в контексте вызывающих абонентов (т. стек не будет выпущен до тех пор, пока вызывающий абонент не вернется)
  • давным-давно alloca перешел из непереносимой функции / взлома в стандартизованное расширение, но некоторое негативное восприятие может сохраняться
  • время жизни привязано к области видимости функции, которая может или не подходит программисту лучше, чем явный контроль malloc
  • , который должен использовать malloc, побуждает думать об освобождении - если это управляемый через функцию обертки (например, WonderfulObject_DestructorFree(ptr)), тогда функция предоставляет точку для операций очистки операций (например, закрытие дескрипторов файлов, освобождение внутренних указателей или выполнение некоторых протоколов) без явных изменений кода клиента: иногда это хорошая модель для последовательно внедряются в этот псевдо-OO-стиль программирования, естественно хотеть что-то вроде WonderfulObject* p = WonderfulObject_AllocConstructor(); - это возможно, когда «конструктор» - это функция, возвращающая память malloc (поскольку память остается выделенной после того, как функция возвращает значение для сохранения в p), но не при использовании «конструктора» s alloca макро-версия WonderfulObject_AllocConstructor могла бы достичь этого, но «макросы злы» в том, что они могут конфликтовать друг с другом и не-макрокодом и создавать непреднамеренные замены и, следовательно, трудно диагностировать недостающие проблемы free операции могут быть обнаружены ValGrind, Purify и т. д., но отсутствующие вызовы «деструктор» не всегда могут быть обнаружены вообще - одно очень незначительное преимущество в плане обеспечения предполагаемого использования; в некоторых реализациях alloca() (например, GCC) используется встроенный макрос для alloca(), поэтому замена временной библиотеки памяти для использования памяти не возможна, как это делается для malloc / realloc / free ( например, электрический забор)
  • некоторые реализации имеют тонкие проблемы: например, из справочной системы Linux: во многих системах alloca () не может использоваться внутри списка аргументов вызова функции, поскольку пространство стека, зарезервированное alloca () появится в стеке в середине пространства для аргументов функции.
  • Я знаю, что этот вопрос отмечен C, но как программист на C ++ я думал, что буду использовать C ++ чтобы проиллюстрировать потенциальную полезность alloca: приведенный ниже код (и здесь в ideone ) создает векторное отслеживание полиморфных типов разного размера, которые выделены в стек (с привязкой времени жизни к возврату функции), а не с распределением кучи .

    #include 
    #include 
    #include 
    
    struct Base
    {
        virtual ~Base() { }
        virtual int to_int() const = 0;
    };
    
    struct Integer : Base
    {
        Integer(int n) : n_(n) { }
        int to_int() const { return n_; }
        int n_;
    };
    
    struct Double : Base
    {
        Double(double n) : n_(n) { }
        int to_int() const { return -n_; }
        double n_;
    };
    
    inline Base* factory(double d) __attribute__((always_inline));
    
    inline Base* factory(double d)
    {
        if ((double)(int)d != d)
            return new (alloca(sizeof(Double))) Double(d);
        else
            return new (alloca(sizeof(Integer))) Integer(d);
    }
    
    int main()
    {
        std::vector numbers;
        numbers.push_back(factory(29.3));
        numbers.push_back(factory(29));
        numbers.push_back(factory(7.1));
        numbers.push_back(factory(2));
        numbers.push_back(factory(231.0));
        for (std::vector::const_iterator i = numbers.begin();
             i != numbers.end(); ++i)
        {
            std::cout << *i << ' ' << (*i)->to_int() << '\n';
            (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                             // program depends on side effects of destructor
        }
    }
    
    2
    задан MatKravi 16 January 2019 в 01:51
    поделиться

    1 ответ

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

    1 2 4 5 4 1
    
    5: 3
    4: 2, 4 (leader)
    3: None
    2: 1
    1: 0, 5
    0: None
    

    Теперь следуйте назад от лидера:

    Who's looking at 4?
      -> 2
    [x, x, 1, x, 0, x]
    
    Who's looking at 2?
      -> 1
    [x, 2, 1, x, 0, x]
    
    Who's looking at 1?
      -> 0 and 5
    [3, 2, 1, x, 0, 3]
    
    Who's looking at 0 or 5?
      -> 3
    [3, 2, 1, 4, 0, 3]
    

    Псевдокод:

    // For each position, we'd like to know
    // which cells are pointing to it
    A = input array
    leader = None
    map = {}
    
    for i=0 to length(A)-1:
      if i = A[i]:
        leader = i
    
      if i != leader:
        if A[i] in map:
          map[A[i]].append(i)
        else:
          map[A[i]] = [i]
    
    
    //Now follow backwards from the leader
    output = Array(length(A))
    next = leader
    output[leader] = 0
    rank = 0
    
    // Assumes the data provides
    // for a straightforward solution.
    // There may be edge cases to work
    // out if that's not the case.
    while next:
      for i in map[next]:
        next = None
        if i in map:
          next = i
          rank = rank + 1
          for j in map[next]:
            output[j] = rank
          break
    
    0
    ответ дан גלעד ברקן 16 January 2019 в 01:51
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: