Search code examples
c++builderindy

TIdTCPServer's TIdContext->Data odd behaviour


To send data to multiple clients I create a TIdThreadSafeStringList in OnConnect and assign it to AContext->Data like so

AContext->Data = new TIdThreadSafeStringList

When the client disconnects, its stringlist is deleted in OnDisconnect like so

delete AContext->Data

However this results in an AV. If I zero the parameter, like so

delete AContext->Data
AContext->Data = NULL

the AV goes away. Is there some auto cleanup I'm not aware of?

Using C++ Builder 10.2.3.


Solution

  • Is there some auto cleanup I'm not aware of?

    Yes. TIdContext derives from TIdTask, which owns the Data property. The TIdTask destructor is called after the OnDisconnect event and will free the Data object if it is not NULL.

    Another (preferred) way to handle this situation is to instead derive a new class from TIdServerContext and add your TIdThreadSafeStringList to that class (and any other per-client custom functionality you want), eg:

    class TMyContext : public TIdServerContext
    {
    public:
        TIdThreadSafeStringList *MyList;
    
        __fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL)
            : TIdServerContext(AConnection, AYarn, AList)
        {
            MyList = new TIdThreadSafeStringList;
        }
    
        __fastcall ~TMyContext()
        {
            delete MyList;
        }
    
        //...
    };
    

    Then assign your class type to the server's ContextClass property at runtime before activating the server, eg:

    __fastcall TMyForm::TMyForm(TComponent *Owner)
        : TForm(Owner)
    {
        IdTCPServer1->ContextClass = __classid(TMyContext);
        //...
    }
    

    Then, you can simply type-cast any TIdContext* pointer belonging to the server to your class type in order to access the TIdThreadSafeStringList (or other functionality):

    static_cast<TMyContext*>(SomeIdContext)->MyList->...
    

    This way, you can ignore the TIdContext::Data property altogether, or use it for other purposes, if desired.