Используя общие методы?

Каковы преимущества и недостатки использования общих методов (во время компиляции, время выполнения, производительность и память)?

5
задан templatetypedef 27 January 2011 в 04:02
поделиться

7 ответов

Хорошо, Java Regies и шаблоны C ++ настолько разные, что я не уверен, что можно ответить на них одним вопросом.

Java Generics

Это в значительной степени для синтаксического сахара. Они реализуются путем противоречивого решения, называемого стиранием типа . Все, что они действительно делают, это помешать вам отменить много, что делает их более безопасными для использования. Производительность идентична для создания специализированных классов, за исключением случаев, когда вы используете то, что было бы необработанным типом данных (Int, Float, Double, Char, Bool, Short). В этих случаях типы значений должны быть введены в систему для их соответствующих ссылочных типов (целое число, поплавок, двойную, CHAR, BOOL, короткому), которое имеет некоторые накладные расходы. Использование памяти идентично, поскольку JRE просто выполняет кастинг на заднем плане (который по существу бесплатный).

Java также имеет какой-то хороший тип ковариации и контравариационные , что заставляет вещи выглядеть намного чище, чем их не использовать.

Шаблоны C ++

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

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

Отредактируйте (спасибо Дэвид Родригес): в то время как общий класс Java компилирует, что это целое я, при использовании шаблона C ++, вы только компилируете то, что вы используете. Итак, если вы создадите STD :: Vector и используйте только Push_back и Размер , только эти функции будут скомпилированы в объектный файл. Это облегчает размер исполняемой задачи.


Если вам интересно различия между ними, проверьте это сравнение дженериков в C #, Java и C ++.

8
ответ дан 13 December 2019 в 05:35
поделиться

Картина истории - это отличная техника планирования, но я бы не использовал карту истории для отслеживания. Я бы использовал функции / сценарии, идентифицированные на карте как ведра функциональности, и я бы использовал графики парковки, чтобы показать прогресс в каждой функции. Хорошая идея состоит в том, чтобы определить минимальную функциональность, необходимую для доставки каждую функцию (конечно, это должно быть самые высокие приоритетные истории для этой функции), и поставить линию на графике парковки для каждой функции, которая показывает, когда это минимальное количество функциональности был реализован. Это четкий способ показывать именно там, где продукт является внешним заинтересованным сторонам.

-121--4904339-

Взгляд на log4jdbc . Это позволяет вам взглянуть на все вещи, которые проходят через JDBC, включая соединения открытия / закрытия, а также информацию о номерах соединения.

-121--2835576-

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

1
ответ дан 13 December 2019 в 05:35
поделиться

В Java (не уверена в Rebalics C ++) - это функция с компиляцией. Они избегают использования потенциально небезопасных каста. Типы коллекции выполняются, например, явно доступны для компилятора, чтобы он знал, какие виды объектов / примитивов можно разместить в нем. Это удаляет небезопасные предположения, сделанные разработчиками о том, что может быть в коллекции в какое-то время. Он также служит для улучшения читаемости кода. В Java я не верю, что на получение возникает производительность или память.

2
ответ дан 13 December 2019 в 05:35
поделиться

Я записал несколько общего полевых и записей классов. Они не используют шаблоны. Классный атрибут состоит в том, что у них есть прочитанный и . Способ , который использует посетитель .

Один хороший атрибут - это то, что вы можете обработать записи, не зная деталей. (BWT, запись состоит из одного или нескольких полей). Таким образом, запись будет прочитана путем прохождения читателя (класс для посетителей для полей для чтения) к каждому полю и имея поле, используйте данный ридер, чтобы заполнить его элементы (ы). Точно с написанием.

Если мне нужно прочитать из файла XML или базы данных, я просто создаю устройство Reader , которое специализируется на чтении от XML или базы данных. Это не требует никаких изменений в записи записи или полевых классов. Хороший, быстрый и легкий.

Один недостаток в том, что я не могу легко увидеть запись в отладчике. Я должен написать код для печати записи или использовать оператор , если включен оператор , когда столкнутся определенная запись.

Я поражен, сколько работы можно выполнить, не зная деталей объектов и прилипав к интерфейсам.

0
ответ дан 13 December 2019 в 05:35
поделиться

Вы также просили недостатки, вот один.

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

Вот пример. Некоторое время назад я написал менеджер ресурсов на основе политики. Вид как умный указатель, но достаточно универсальный, который будет использоваться для любого рода ресурса, а не просто память. Такие вещи, такие как Mutexes, GDI (Windows) ресурсы и т. Д. Мотивация написания записью это было два раза. Один, я просто хотел написать это :) Но два, я хотел создать репозиторий кода, который может быть, как правило, полезно для управления ресурсами всех видов. Для того, чтобы он был вообще полезен, люди должны были бы захотеть использовать его.

Итак, позвольте мне спросить вас, вы бы хотели использовать это?

    /*** COPY POLICIES ***/
    class SimpleCopyPolicy
    {
    public:
        template<class Resource> Resource copy(const Resource& rhs) const { Resource ret = rhs; return ret; }
    protected:
        ~SimpleCopyPolicy(){};
    };

    class DuplicateHandleCopyPolicy
    {
        public:
            HANDLE sourceProcess, targetProcess;
            DWORD access, options;
            BOOL inherit;

            DuplicateHandleCopyPolicy(HANDLE sourceProcess_=GetCurrentProcess(), HANDLE targetProcess_=GetCurrentProcess(), DWORD access_=0, BOOL inherit_=FALSE,DWORD options_=DUPLICATE_SAME_ACCESS)
            : sourceProcess(sourceProcess_), targetProcess(targetProcess_), access(access_), inherit(inherit_), options(options_) {}

            template<class Resource> Resource copy(const Resource & rhs) const
            {
                Resource ret;
#               if defined(VERBOSE_STLEXT_DEBUG) & defined(MHDAPI)
                if( !verify( DuplicateHandle(sourceProcess, rhs, targetProcess, &ret, access, inherit, options) ))
                {
                    DWORD err = GetLastError();
                    mhd::WarningMessage("DuplicateHandleCopyPolicy::copy()", "Error %d Copying Handle %X : '%s'",
                    err, rhs, stdextras::strprintwinerr(err).c_str() );
                }
                else
                    mhd::OutputMessage("Duplicated %X to %X", rhs, ret);
#               else
                DuplicateHandle(sourceProcess, rhs, targetProcess, &ret, access, inherit, options);
#               endif
                return ret;
            }

        protected:
            ~DuplicateHandleCopyPolicy(){};
    };

    /*** RELEASE POLICIES ***/
    class KernelReleasePolicy
    {
    public:
        template<class Handle> bool release(Handle& h)
        {
#           if defined(VERBOSE_STLEXT_DEBUG) & defined(MHDAPI)
            OutputMessage("Closing %X", h);
#           endif
            return 0 != CloseHandle(h);
        }
    };
    class CritsecReleasePolicy
    {
    public:
        template<class Handle> bool release(Handle& h)
        {
            DeleteCriticalSection(&h);
            return true;
        }
    protected:
        ~CritsecReleasePolicy() {};
    };
    class GDIReleasePolicy
    {
    public:
        template<class Handle> bool release(Handle h) { return 0 != DeleteObject(h); }
    protected:
        ~GDIReleasePolicy(){};
    };
    class LibraryReleasePolicy
    {
    public:
        template<class Handle> bool release(Handle h) { return 0 != FreeLibrary(h); }
    protected:
        ~LibraryReleasePolicy(){};
    };
#   ifdef WINSOCK_VERSION
    class SocketReleasePolicy
    {
    public:
        template<class Handle> bool release(Handle h) { return 0 != closesocket(h); }
    protected:
        ~SocketReleasePolicy(){};
    };
#   endif

    class DestroyWindowPolicy
    {
    public:
        template<class Handle> bool release(Handle h) { return 0 != DestroyWindow(h); }
    protected:
        ~DestroyWindowPolicy() {};
    };

    /*** LOCKING POLICIES ***/
    class WFSOPolicy    // Wait For Single Object
    {
    public:
        WFSOPolicy(DWORD timeout_=INFINITE) : timeout(timeout_) {};

        template<class Handle> bool wait(Handle& h) const
        {
#           if defined(VERBOSE_STLEXT_DEBUG) & defined(MHDAPI)
            DWORD ret = ::WaitForSingleObject(h,timeout);
            if( !verify( WAIT_OBJECT_0 == ret ))
            {
                DWORD err = GetLastError();
#               ifdef UNICODE
                mhd::WarningMessage("WFSOPolicy", "Error %d Waiting for object %X [Timeout %s] : '%S'",
                    err, h, INFINITE==timeout?"INFINITE":std::formatstr("%d ms", timeout).c_str(),
                    stdextras::strprintwinerr(err).c_str() );
#               else
                mhd::WarningMessage("WFSOPolicy", "Error %d Waiting for object %X [Timeout %s] : '%s'",
                    err, h, INFINITE==timeout?"INFINITE":std::formatstr("%d ms", timeout).c_str(),
                    stdextras::strprintwinerr(err).c_str() );
#               endif
                return false;
            }
            return true;
#           else
            return WAIT_OBJECT_0 == ::WaitForSingleObject(h,timeout);
#           endif
        }

        DWORD timeout;
    };


    /*** LOCK/UNLOCK POLICIES ***/
    class CritsecLockPolicy  // CRITICAL_SECTION lock/unlock policies
    {
    public:
        template<class Handle> bool lock(Handle& h)
        {
            EnterCriticalSection(const_cast<CRITICAL_SECTION*>(&h));
            return true;
        }
        template<class Handle> bool unlock(Handle& h) 
        {
            LeaveCriticalSection(&h);
            return true;
        }
    };

    template<DWORD waitTimeout = INFINITE>
    class MutexLockPolicy : public WFSOPolicy
    {
    public:
        MutexLockPolicy() : WFSOPolicy(waitTimeout) {};
        template<class Handle> bool lock(Handle& h) const
        {
            return wait(h);
        }
        template<class Handle> bool unlock(Handle& h) const 
        {
            return 0 != ReleaseMutex(h);
        }
    };

    class PlaceboLockPolicy // this lock policy doesnt actually do anything!  useful for debugging & experimentation
    {
    public:
        PlaceboLockPolicy() {};
        template<class Handle> bool lock(Handle&) const
        {
            return true;
        }
        template<class Handle> bool unlock(Handle&) const
        {
            return true;
        }
    };


    template<class Resource, typename ReleasePolicy, typename CopyPolicy = SimpleCopyPolicy>
    class simple_auto_resource : public ReleasePolicy, public CopyPolicy
    {
    public:
        typedef simple_auto_resource<Resource,ReleasePolicy,CopyPolicy> base_type;

        simple_auto_resource() : res(0) {}
        simple_auto_resource(const Resource & r) : res(copy(r)) {}
        ~simple_auto_resource() { if(res) release(res); }

        void clear() { if(res) release(res); res = 0; }

        Resource& get() { return res; }
        const Resource& get() const { return res; }

        Resource detach() { Resource ret = res; res = 0; return ret; }

        operator const Resource&() const { return get(); }
        operator Resource&() { return get(); }

        base_type& operator=(const Resource& rhs) { clear(); res = copy(rhs); return * this; }

        template<class Comp> bool operator==(const Comp& rhs) const { return res == (Resource)rhs; }
        template<class Comp> bool operator!=(const Comp& rhs) const { return res != (Resource)rhs; }
        template<class Comp> bool operator<(const Comp& rhs) const { return res < (Resource)rhs; }
    private:
        Resource res;
    };

    typedef simple_auto_resource<HBRUSH,GDIReleasePolicy> auto_brush;
    typedef simple_auto_resource<HINSTANCE, LibraryReleasePolicy> auto_lib;
    typedef simple_auto_resource<CRITICAL_SECTION, CritsecReleasePolicy> auto_critsec;
    typedef simple_auto_resource<HWND,DestroyWindowPolicy> auto_destroy_hwnd;
    typedef simple_auto_resource<HANDLE,KernelReleasePolicy,DuplicateHandleCopyPolicy> auto_kernelobj;  
#   ifdef WINSOCK_VERSION
    typedef simple_auto_resource<SOCKET,SocketReleasePolicy> auto_socket;
#   endif

    typedef auto_kernelobj auto_mutex;
    typedef auto_kernelobj auto_event;
    typedef auto_kernelobj auto_filehandle;
    typedef simple_auto_resource<HANDLE,KernelReleasePolicy> auto_localkernelobj;   
    typedef simple_auto_resource<HANDLE,KernelReleasePolicy> auto_localmutex;   
    typedef simple_auto_resource<HANDLE,KernelReleasePolicy> auto_localevent;   
    typedef simple_auto_resource<HANDLE,KernelReleasePolicy> auto_thread;   
    typedef simple_auto_resource<HMODULE,KernelReleasePolicy> auto_hmodule;

Если ваш ответ «Нет, слишком сложный», - это именно моя точка зрения.

-1
ответ дан 13 December 2019 в 05:35
поделиться

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

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

2
ответ дан 13 December 2019 в 05:35
поделиться

Проверьте эти отличные статьи о планах выполнения на simple-talk.com:

Они также имеют бесплатную электронную книгу Планы выполнения SQL Server для загрузки.

-121--4244837-

Помимо установки WrapMode для DefureCellStyle можно выполнить следующие действия:

  1. Необходимо присвоить свойству EditingControlShowing Event
  2. Cast Control EventArgs нужный тип (например, текстовое поле, флажок или кнопка)
  3. С помощью этого типоразмера измените свойство Multiline следующим образом:
private void MyGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    TextBox TB = (TextBox)e.Control;
    TB.Multiline = true;            
}
-121--1157096-

Основным преимуществом обоих языков является безопасность типа: например, компилятор гарантирует, что Список < Foo > список будет содержать только объекты Foo . Без дженериков (например, в более ранних версиях Java) список будет принимать любой класс, наследующий Object .

Производительность Java отличается от C++. В C++ универсальный класс специализирован во время процесса компиляции, поэтому накладные расходы отсутствуют.

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

Наконец, своего рода связанные, когда дженерики были представлены на Java, они также добавили автобоксинг, который позволяет использовать примитивные типы с дженериками. Автобоксирование означает, что примитивный тип автоматически упаковывается в эквивалентный класс, т.е. int помещается в объект Integer при его использовании в универсальном контексте. Это снова добавляет накладные расходы времени выполнения, поскольку сначала должен быть создан новый экземпляр Integer , а затем собран мусор.

0
ответ дан 13 December 2019 в 05:35
поделиться
Другие вопросы по тегам:

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