Открытие TStream на stdin/stdout в приложении консоли Delphi

По-прежнему не рекомендуется использовать alloca, почему?

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

  • C99 предоставляет массивы переменной длины, которые часто используются преимущественно как обозначения, более совместимые с массивами фиксированной длины и интуитивно понятными в целом
  • многие системы имеют меньше общей памяти / адресного пространства, доступного для стека, чем для кучи, что делает программу несколько более восприимчивой к исчерпанию памяти (через переполнение стека): это может рассматриваться как хорошая или плохая вещь - один из-за того, что стек автоматически не увеличивается, как это делает куча, состоит в том, чтобы предотвратить неконтролируемые программы, оказывающие столь же неблагоприятное влияние на всю машину
  • при использовании в более локальной области действия (такой как while или for) или в нескольких областях объем памяти накапливается за одну итерацию / область действия и не освобождается до выхода из функции: это контрастирует с нормальными переменными, определенными в области действия структуры управления (например, for {int i = 0; i < 2; ++i) { X } будет накапливаться alloca память запрашивается в X, но память для массива фиксированного размера будет перерабатывается за итерацию).
  • современные компиляторы, как правило, не inline выполняют функции, которые вызывают alloca, но если вы их принудительно заставите, то alloca произойдет в контексте вызывающей стороны (т. Е. Стек не будет освобожден до тех пор, пока вызывающая сторона не вернется)
  • давно alloca перешли от непереносимой функции / хака к стандартизированному расширению, но некоторое негативное восприятие может сохраняться
  • время жизни связано с областью действия функции, которая может или может не подойти программисту лучше, чем явный элемент управления malloc
  • необходимость использовать malloc побуждает задуматься о освобождении - если это управляется через функцию-обертку (например, WonderfulObject_DestructorFree(ptr)), то функция обеспечивает точка для выполнения операций очистки (таких как закрытие файловых дескрипторов, освобождение внутренних указателей или ведение некоторого ведения журнала) без явных изменений в клиентском коде: иногда это хорошая модель для последовательного принятия
    • в этом псевдо-ОО-стиле программирования естественно хотеть что-то вроде WonderfulObject* p = WonderfulObject_AllocConstructor(); - это возможно, когда onstructor "- это функция, возвращающая память malloc (так как память остается выделенной после того, как функция возвращает значение, которое будет сохранено в p), но не в том случае, если« конструктор »использует alloca
      • Макро-версия WonderfulObject_AllocConstructor могла бы достичь этого, но «макросы - это зло» в том смысле, что они могут конфликтовать друг с другом и не-макрокодом и создавать непреднамеренные замены и вытекающие из этого проблемы, которые трудно диагностировать li> ul>
      • пропущенные 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
        }
    }
    
28
задан Joe White 29 June 2009 в 21:13
поделиться