Шаблон CList

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Этот шаблон я использую как динамический список для объектов, кроме примитивных (для них я создаю специализированные классы).

#pragma once

typedef struct _NODE
{
    void * Data;
    struct _NODE * Next;

} * PNODE, NODE;


template < class T > 
class CList
{
private:
    PNODE _head;
    PNODE _tail;

protected:
    CList & _self;

private:
    T & GetItem( int index )
    {
        PNODE pNode = _head;

        while ( index-- )
        {
            if ( pNode == NULL )
            {
                break;
            }

            pNode = pNode->Next;
        }

        return * reinterpret_cast< T * >( pNode->Data );
    }

public:
    int Count;

public:
    CList() : _self( * this )
    {
        _head = NULL;
        _tail = NULL;

        Count = 0;
    }


    explicit CList( const CList<T> & obj )
    {
        Clear();

        AddRange( obj );
    }


    ~CList()
    {
        Clear();
    }

       
    CList<T> & operator=( const CList<T> & copy )
    {
        while ( Count > 0 )
        {
            RemoveAt( 0 );
        }

        for ( int n = 0; n < copy.Count; n++ )
        {
            Add( new T ( copy[n] ) );
        }

        return * this;
    }


    // Setter.
    T & operator[]( int index )
    {
        return GetItem( index );
    }


    // Getter.
    T & operator[]( int index ) const
    {
        return const_cast< CList<T> * >( this )->GetItem( index );
    }

    
    bool Empty()
    {
        return Count == 0;
    }


    T * Add( T * item )
    {
        if ( item == NULL ) return NULL;

        PNODE node = new NODE;

        if ( node == NULL )
        {
            return NULL;
        }

        node->Data = item;
        node->Next = NULL;

        if ( Count == 0 )
        {
            _head = node;
        }
        else
        {
            _tail->Next = node;
        }

        _tail = node;

        Count++;

        return item;
    }


    void AddRange( const CList<T> & source )
    {
        for ( int n = 0; n < source.Count; n++ )
        {
            Add( & source[n] );
        }
    }   


    void RemoveAt( int index )
    {
        if ( index > Count - 1 ) return;

        PNODE Curr = _head, Prev = NULL;

        int n = index;

        if ( Curr != NULL )
        {
            while ( n-- )
            {
                Prev = Curr;
                Curr = Curr->Next;
            }

            if ( index == 0 )
            {
                _head = Curr->Next;
            }
            else
            {
                Prev->Next = Curr->Next;
            }

            delete Curr;

            Count--;
        }
    }


    void Clear()
    {
        while ( Count > 0 )
        {
            RemoveAt( 0 );
        }
    }
};

 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Для любителей C++. Пример использования (взято из моей программы, где я подключаю прерывания динамически по своему алгоритму).

Interrupts.h

typedef struct _INTERRUPT
{
    uint16_t Vector;
    void ( * FuncPtr )( void * );
    void * Data;
} *PINTERRUPT, INTERRUPT;


class CInterrupts : public CList< INTERRUPT >
{
private:
    //TMutex _mutex;

private:
    int indexOf( uint16_t vect );
    PINTERRUPT get( uint16_t vect );
    bool exists( uint16_t vect );
    void config( uint16_t vect );

public:
    CInterrupts();
    ~CInterrupts();

    int IndexOf( uint16_t vect );
    PINTERRUPT Get( uint16_t vect );
    PINTERRUPT Attach( uint16_t vect, void ( * userFunc )( void * ), void * data );
    void Detach( uint16_t vect );
    bool Exists( uint16_t vect );
};

Interrupts.cpp

#include "Interrupts.h"

void nothing( void * ) {}

CInterrupts::CInterrupts() : CList< INTERRUPT >()
{
}


CInterrupts::~CInterrupts()
{
    Clear();
}


int CInterrupts::indexOf( uint16_t vect )
{
    for ( int n = 0; n < Count; n++ )
    {
        PINTERRUPT item = & _self[n];

        if ( item != NULL )
        {
            if ( item->Vector == vect )
            {
                return n;
            }
        }
    }

    return -1;
}


PINTERRUPT CInterrupts::get( uint16_t vect )
{
    int index = indexOf( vect );

    if ( index != -1 )
    {
        return & _self[ index ];
    }

    return NULL;
}


bool CInterrupts::exists( uint16_t vect )
{
    int index = indexOf( vect );

    return index != -1;
}

void CInterrupts::config( uint16_t vect )
{
    switch ( vect )
    {
        case INT0_vect_num:
            EIMSK &= ~( 1 << INT0 );
            EICRA |= ( 1 << ISC00 ) | ( 1 << ISC01 );
            EIMSK |= ( 1 << INT0 );
            break;
    }
}

PINTERRUPT CInterrupts::Attach( uint16_t vect, void ( * userFunc )( void * ), void * data )
{
    //TMutexLocker lock( _mutex );

    PINTERRUPT interrupt = NULL;

    if ( exists( vect ) )
    {
        interrupt = get( vect );
        interrupt->FuncPtr = userFunc;
        interrupt->Data;
    }
    else
    {
        interrupt = ( PINTERRUPT ) new INTERRUPT;

        interrupt->Vector = vect;
        interrupt->FuncPtr = userFunc;
        interrupt->Data;

        reinterpret_cast< CList<INTERRUPT> * >( this )->Add( interrupt );
    }

    config( vect );

    return interrupt;
}


void CInterrupts::Detach( uint16_t vect )
{
    //TMutexLocker lock( _mutex );

    if ( exists( vect ) )
    {
        PINTERRUPT interrupt = get( vect );
        interrupt->FuncPtr = nothing;
        interrupt->Data = NULL;
    }
}


int CInterrupts::IndexOf( uint16_t vect )
{
    //TMutexLocker lock( _mutex );

    return indexOf( vect );
}


PINTERRUPT CInterrupts::Get( uint16_t vect )
{
    //TMutexLocker lock( _mutex );

    return get( vect );
}


bool CInterrupts::Exists( uint16_t vect )
{
    //TMutexLocker lock( _mutex );

    return exists( vect );
}

 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Другой пример. Элемент иерархического меню с использованием CList. Очень удобно делать меню. Только заголовочный файл.

class CMenuItem
{
protected:
    CList< CMenuItem > _visibleItems;

private:
    void Initialize();
    void Initialize( char * text );
    void Initialize( char * text, CMenuItem * parent );
    void Initialize( char * text, CMenuItem * parent, ClickHandler click );
    void Initialize( char * text, CMenuItem * parent, ClickHandler click, void * tag );

public:
    bool Visible;
    int SelectedIndex;
    int TopIndex;

    char * Text;
    void * Tag;
    CMenuItem * Parent;
    CList< CMenuItem > Items;

public:
    CMenuItem();
    explicit CMenuItem( char * text );
    CMenuItem( char * text, CMenuItem * parent );
    CMenuItem( char * text, CMenuItem * parent, ClickHandler click );
    CMenuItem( char * text, CMenuItem * parent, ClickHandler click, void * tag );
    CMenuItem( const CMenuItem & obj );
    ~CMenuItem();

    void MoveDown();
    void MoveUp();

    void OnActivate();
    void OnPaint();
    void OnTimer( WPARAM wParam );
    void OnKeyDown( UINT code );
    void OnClick( void * sender );

    char * ToString();
    CMenuItem * SelectedItem();
};

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

uni пишет:

Этот шаблон я использую как динамический список

Молодец!

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Я пытался использовать stl для avr, но он тяжеловат.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

здесь тебя за это никто не похвалит.  Не жди. 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

uni пишет:

хвалить буду я, если поймёте как это работает и сможете использовать. Кто сможет, тому будет большое облегчение при работе с коллекцией объектов неизвестного размера и произвольного типа.

Понятно.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

И помни, что: "Хотя шаблоны предоставляют краткую форму записи участка кода, на самом деле их использование не сокращает исполняемый код, так как для каждого набора параметров компилятор создаёт отдельный экземпляр функции или класса."

Механизм шаблонов для этих огрызков не предназначен. Использовать то, канеш, можно.  Но принесет ли это нам радость?

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно. 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Это не так, как уже много лет как показано тут. На easyelectrinics много лет тому назад была серия статей, где проводился анализ ассемблерного года при использовании шаблонов. Так что ... идти и читать статьи от neiver.

Я везде на avr использую его шаблон умных указателей для работы с памятью программ. Очень удобно и код такой же как без них по объёму.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

и это, 

039 public:
040

int Count;

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

И помни, что: "Хотя шаблоны предоставляют краткую форму записи ...

Коллега - википедик? :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

скорее, всёподрядчитатель.  C# шаблоны мне нравюца больше. 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Я могу показать рабочий код, который достаточно хорошо имитирует свойства в C++, но это сложнее, чем CList, народ не поймёт вообще. Поэтому используется публичное поле. Если использовать функции, то это будут setter и getter. Я не перфикционист, мне достаточно публичного поля.

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно. 

Точней к указателям на что угодно. И про громоздкость компиляции шаблонов, тоже общеизвестно, потому действительно на МК предложеный подход плох. А уж про необходимость иметь " коллекцией объектов неизвестного размера и произвольного типа." - вобще не встречается на МК при правильном проектировании задачи (ну не ориентироватся же на приблудившихся вебдизайнеров желающих хранить произвольные переменные с произвольными именами). Максимум встречается неизвестное кол-во известных датчиков, и соответственно данных под них. А при подробном рассмотрении и количество очень даже ограничено аппаратно.

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

Автору не останавливатся boost на avr еще загадочней и бесполезней.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Кто не страдает стереотипами, тот возьмёт на вооружение, остальные останутся со своими word'ами.

П.С. Где я использую этот шаблон:

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

- при загрузке внешних данных, например, информации о тегах для modbus, которые должны быть расположены в массиве неизвестного заране размера (определяется внешним файлом);

- при создании фреймов запросов для modbus, они формируются на основании тегов и создаются при загрузке один раз;

- при создании окон для графического индикатора;

и т.д.

Очень удобно иметь типизированный шаблон :)

Logik
Offline
Зарегистрирован: 05.08.2014

Понятно. Код для оригиналов,неформалов,  нетрадициалов и личностей в состоянии расширеного сознания. 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Logik пишет:

Понятно. Код для оригиналов,неформалов,  нетрадициалов и личностей в состоянии расширеного сознания. 

нужно брать - дайте два

Logik
Offline
Зарегистрирован: 05.08.2014

ну вот ТС boost под avr допишет - будет два )))

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

DetSimen пишет:

гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно. 

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

Logik
Offline
Зарегистрирован: 05.08.2014

Странная порода эволюционировала с развитием IT. STL и Boost они знают, а односвязній список им "покажи". uni, читайте класику )))

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Logik, этот список реализован у меня, раскрой спойлер с исходником. Мне не понятно чем List с word'ами будет отличаться?

У меня void * - этот тот же word в архитекуре avr. Я поэтому и спрашиваю, чем List word'ов отличается от List'а word'ов?

Правка. Может это не ясно из примеров, но CList содержит указатели на экземпляры классов. При добавлении элемента нужно в качестве параметра передавать его адрес. Т.е. вы выделяете память под ваш тип и полученный адрес передаёте списку. Объекты сами в списке не хранятся. 

Logik
Offline
Зарегистрирован: 05.08.2014

//Мне не понятно чем List с word'ами будет отличаться?

Это хреново. Должен бы понимать, что в односвязном списке есть только одна операция естественно следующая из его структуры. Это GetNext. Используя её легко строится все, например поиск элемента, в один проход. А как будет выглядеть поиск в твоем коде и за сколько проходов? Хреново что ты такого не понимаеш, а на чето претендуеш.

ПС. А уж то, что при умении работать с односвязным списком за один проход делается и поиск множества по различным сложным критериям, возможно с попутным внесением изменений в некоторые элементы, возможно с удалением некоторых элементов или копированием их или выводом нахер и пр. любителям либ не интересно. Им только интересно, чего их либа так тормозит то ;)

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Logik пишет:

//Мне не понятно чем List с word'ами будет отличаться?

Это хреново. Должен бы понимать, что в односвязном списке есть только одна операция естественно следующая из его структуры. Это GetNext. Используя её легко строится все, например поиск элемента, в один проход. А как будет выглядеть поиск в твоем коде и за сколько проходов? Хреново что ты такого не понимаеш, а на чето претендуеш.

Да уж... поиск элемента по индексу реализован в методе GetItem(), где твой GetNext() это вот этот код:

pNode = pNode->Next
Logik
Offline
Зарегистрирован: 05.08.2014

Чудо! Там поиск по номеру а я по элементу хочу. А номер в односвязном, то вобще ни о чем. Удалил элемент - вся нумерация поплыла. Так что индексом его громко не называй, однозначного соответствия между ним и данными нет.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Logik, лучше больше не комментируй... люди о тебе мнение составят... далекое от того, о чём ты сам о себе думаешь. Открой лучше спойлер с кодом и попробуй всё-таки понять как это работает.

Logik
Offline
Зарегистрирован: 05.08.2014

Я понял, предметный разговор ты окончил, т.к. осознал дибилизм своего творения. И решил перейти на личности. 

Если захочеш вернутся в цивилизацию то оцени порядок сложности поиска элемента в своем творении. Для односвязного списка он известен O(n).

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

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

На личности ты переходишь. Я пытаюсь заставить тебя код прочитать, а ты всё глупостями в мой адрес сыплешь. Выше человек сделал правильное замечание по поводу поля Count. Бери с него пример и хватит нести ахинею всякую. Что ни пост, то 2 х 2.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

А я говорил, что тебе здеся будут не рады... 

Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами, а основная масса, которая здесь тусуется, начинают темы со слов "помогите новичку вынести горшок".  Им то что ты написал - настолько дико, что использовать это никто не будет, зато охотно забросают тебя калом по самые нихачу. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да ладно Вам, Logic, ну написал человек как ему нравится, и молодец. То, что в реализации "списка" нет классических операций car и cdr, зато есть какие-то индексы, меня тоже несколько удивило, а реализация функции Clear() так вообще в восторг привела! Но, видать такие они - нынешние списки :) В любом случае, этот пост гораздо приятнее вопросов "почему функция if  не компилируется?".

Logik
Offline
Зарегистрирован: 05.08.2014

Понятнно, uni, ниосилил оценить сложность своего творения)) А она квадратична, т.к. внутри цикла по все элементам будет лежать цикл поиска заданого по индексу, который в среднем будет прокручиватся до половины списка, потому n*n/2.  Т.е. при наличии 1000 элементов в спмске и 10мксек на обработку элемента в односвязном списке мы найдем элемент не хуже чем за  10мсек. А в приведеном классе за 5сек.

Тема откуда берутся тормознутые проги и програмисты раскрыта полностью. Надеюсь и ответ на "Мне не понятно чем List с word'ами будет отличаться?" тоже понят.

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

А я говорил, что тебе здеся будут не рады... 

Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами, а основная масса, которая здесь тусуется, начинают темы со слов "помогите новичку вынести горшок".  Им то что ты написал - настолько дико, что использовать это никто не будет, зато охотно забросают тебя калом по самые нихачу. 

Тонкое понимание вопроса, однако)))  Да. Согласен.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

DetSimen пишет:

Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами

Не впервой. А что значит не раздувая код шаблонами? Т.е. если мне нужно 4 таких списка, но каждый с разным типом объекта, то как будет выглядеть нераздутый код? Неужели он будет прям настолько нераздутым? Что аж никто до сих пор не осмелился показать свой вариант. Если это список word'ов, то это совершенно ничем не отличается от варианта с шаблоном, кроме неудобства приведения.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Logik пишет:

Понятнно, uni, ниосилил оценить сложность своего творения)) А она квадратична, т.к. внутри цикла по все элементам будет лежать цикл поиска заданого по индексу, который в среднем будет прокручиватся до половины списка, потому n*n/2.  Т.е. при наличии 1000 элементов в спмске и 10мксек на обработку элемента в односвязном списке мы найдем элемент не хуже чем за  10мсек. А в приведеном классе за 5сек.

Тема откуда берутся тормознутые проги и програмисты раскрыта полностью. Надеюсь и ответ на "Мне не понятно чем List с word'ами будет отличаться?" тоже понят.

Это было бы дельным замечанием, если бы у меня была реализована функция поиска. Поскольку ты спойлер с шаблоном не открывал, то не знаешь, что функции поиска там нет. В шаблоне есть метод получения элемента по индексу.

Если тебе нужен метод поиска, то он делается точно также как GetItem(), только в качестве параметра передаётся специальный указатель на функцию, получающую на входе элемент и возвращающую на выходе true или false. Поскольку он будет реализован также как GetItem(), то и работать он будет как O(n).

У меня нет такого функционала, т.к. он мне не был нужен. Ты решал свои задачи, а я свои. Моей задачей было - не дублировать лишний код при работе с динамическими списками (у меня их много) и получение доступа к конкретному элементу. Даже очистка и удаление сделаны чисто для некоторой завершённости. Пользоваться ими нужно с умом, а лучше не пользоваться.

Если я удалю элемент в списке при помощи RemoveAt(), то связность от этого не нарушится, т.к. в коде предусмотрено "сшивание" соседних узлов списка.

Если расширять шаблон, то я бы сделал варианты запросов из Linq в C#, но это отдельная работа.

Ещё раз. Внутри шаблона все переходы по списку работают непосредственно с указателями, о чём я указывал выше. То, что у меня не реализована функция поиска... ну, извините, я могу показать как её добавить и как использовать. А писать всякие домыслы о несуществующем (воображаемом) коде ... как вообразите - то и получите.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Я понял, Logik, чего ты хочешь. Тебе нужен итератор. Ну, извини, итератора у меня нет. Предполагается, что итерирования не нужно. Шаблон должен предоставлять нужные методы, скрывая перебор, т.е. если тебе нужен поиск, то нужно реализовать его внутри шаблона, скрыв перебор по элементам. Вручную перебирать элементы не нужно.

Если бы я написал функцию поиска, то её использование выглядело бы как-то так:

TItem * pItem = list.Find( [](x) => { return x.Field == 0; } );

Не помню точно как должно выглядеть лямбда выражение. Внутри шаблона при этом реализуется Find() как я указал выше. Мне лично итераторы не нужны.

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

uni пишет:

Не впервой. А что значит не раздувая код шаблонами? Т.е. если мне нужно 4 таких списка, но каждый с разным типом объекта, то как будет выглядеть нераздутый код? Неужели он будет прям настолько нераздутым? Что аж никто до сих пор не осмелился показать свой вариант. Если это список word'ов, то это совершенно ничем не отличается от варианта с шаблоном, кроме неудобства приведения.

т.е, если тебе нужно 4 таких списка, с разным типом объекта, то компилятор создаст 4 разных класса, функции которого будут заточены под конкретный тип объекта, так, насколько я понимаю, работает механизм шаблонов в С++.  Разделять код между экземплярами классов не выйдет.  Зато такого не случится, сделай ты список хранящий void *. Кастовать конечно придется вручную, ну дак мы и не в сказку попали же.  Это Си, матьиво. 

С другой стороны, я могу ошибаться. Многоуважаемые гуру поправят меня. 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Хм, это можно проверить. Я могу показать листинги компиляции для какого-нибудь предложенного примера. У меня есть возможность удобно их получать.

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

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

Logik
Offline
Зарегистрирован: 05.08.2014

uni пишет:

Я понял, Logik, чего ты хочешь. Тебе нужен итератор. Ну, извини, итератора у меня нет. 

Не. непонял. Хотя либа с итератором было бы эффективней.

Мне нужно, если уж деле дошло до односвязного списка (что повторяю, для МК не типичная задача) и поиска в нем, такие строчки.

        while ( pNode )
        {
            if (  TEST_DATA(pNode->Data ))
            {
                break;
            }

            pNode = pNode->Next;
        }

а может в другой точке

        while ( pNode )
        {
            if (  TEST_DATA(pNode->Data ))
            {
                PNODE node = new NODE;
                node->Next=pNode->Next;
                pNode->Next=node;
                break;
            }

            pNode = pNode->Next;
        }

или

        while ( pNode )
        {
            if (  TEST_DATA(pNode->Data ))
            {
                (word)pNode->Data=millis();
            }

            pNode = pNode->Next;
        }

а может


        while ( pNode )
        {
            ( (word)pNode->Data)++;
            pNode = pNode->Next;
        }

Это быстро просто и эффективно. Да, конечно, можна завернуть в шаблоны это  while ( pNode ) {...; pNode=pNode->Next;}, сделать итераторы, лямды, хулямды и т.д. Только не факт что вобще чего сэкономится, цикл примитивен. Он прост даже для новичка, если он не будет тратить время на твой код под спойлером, а прочитает за то же время статью по односвязным спискам. 

Вот и видим два пути для новичка:

1. Изучить конкретную либу, собственно её интерфейс и примеры применения, заюзать,  затем посреди проекта столкнутся с её неэффективностью. Прибежать на форум с криками "памагите", "где найти другую либу" и пр. При этом оставатся в полной уверености что главное в програмировании - найти нужную либку. Вот и получится продвинутый владеющий десятками либ, тормознутых и глюкавых в разной степени, и абсолютно не понимающий суть процесса изнутри. Ему вечно не хватает, то ОЗу, то скорости проца, то новой либы.

2. Изучить теорию по односвязным спискам и писать эти 3-5 строк по мере надобности в том виде как нужно по месту получать максимально эффективное решение задачи. При этом комбинируя и перебирая варианты обработки данных для оптимизации учитывая специфику. С таким уже хоть есть о чем поговорить по сути.

 

 

uni пишет:

TItem * pItem = list.Find( [](x) => { return x.Field == 0; } );

TItem * pItem = list.Find( [](TItem * x) ->bool { return x.Field == 0; } );

Но старые ИДЕ не поддерживают.

 

uni пишет:

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

Нафига проверять прописные истины?

ПС. Я не противник либ вобще, есть к примеру CriptoLib,  GZIP и др. действительно необходимые вещи. Если кто решится им конкурента написать, зовите, почитаю. А писать тормознутую, глюкавую хрень и пускать её в народ не надо. Не хороше так с народом поступать.