2012-01-20 3 views
5

Mam problem polegający na tym, że muszę wcześniej utworzyć instancje obiektów , ponieważ muszę podłączyć sygnały przez niektóre głębokie prawa własności i chciałbym wymyślić sposób zapisywania i przesyłania szczelin, aby móc budować obiekty bliżej na swojej stronie użycia, zamiast robić to jako zmienne członkowskie.Jak mogę przechowywać i przekazywać gniazda za pomocą metody boost :: signals2?

Mój podstawowy problem polega na tym, że mam proces, który pobiera plik aktualizacji w oddzielnym wątku i wysyła sygnał postępu do każdego zainteresowanego, który jest interesujący . Sygnał jest zasadniczo:

typedef boost::signals2::signal<void (double)> DownloadProgress; 

Załóżmy, że realizacja funkcji progress wspomniano poniżej jest zgodny z tym; charakter samego sygnału nie jest bardzo ważny (chociaż w większości korzystam z funktorów).

Sygnał jest ustawiony i kod nazywany jest coś takiego:

Updater updater; 
updater.onDownloadProgress(&progress); 
updater.runDownloadTask(); 

Po wywołaniu updater.runDownloadTask(), rozpocznie się UpdaterDownloadTask, który uruchamia HTTPRequest i zwraca HTTPResponse. HTTPResponse to element, który wchodzi w interakcję z warstwą sieciową i odbiera dane oraz zawiera sygnał o numerze. Z tym, moja realizacja wygląda nieco jak (bottom-up z HTTPResponse, mocno skrócona do abstrahować metod, które nie są szczególnie ilustracyjne):

class HTTPResponse 
{ 
public: 
    // this will be called for every "chunk" the underlying HTTP 
    // library receives 
    void processData(const char* data, size_t size) 
    { 
    // process the data and then send the progress signal 
    // assume that currentSize_ and totalSize_ are properly set 
    progressSignal_(currentSize_ * 100.0/totalSize_); 
    } 

    void onDownloadProgress(const DownloadProgress::slot_type& slot) 
    { 
    progressSignal_.connect(slot); 
    } 

private: 
    DownloadProgress progressSignal_; 
}; 

class HTTPRequest 
{ 
public: 
    HTTPRequest() : response_(new HTTPResponse) { } 

    void onDownloadProgress(const DownloadProgress::slot_type& slot) 
    { 
    response_->connect(slot); 
    } 

    boost::shared_ptr<HTTPResponse> perform() 
    { 
    // start the request, which operates on response_. 
    return response_; 
    } 

private: 
    boost::shared_ptr<HTTPResponse> response_; 
}; 

class UpdaterDownloadTask : public AsyncTask 
{ 
public: 
    DownloadTask() : request_(new HTTPRequest) { } 

    void onDownloadProgress(const DownloadProgress::slot_type& slot) 
    { 
    request_->connect(slot); 
    } 

    void run() 
    { 
    // set up the request_ and: 
    request_>perform(); 
    } 

private: 
    boost::shared_ptr<HTTPRequest> request_; 
}; 

class Updater 
{ 
public: 
    Updater() : downloadTask_(new UpdaterDownloadTask) { } 
    void onDownloadProgress(const DownloadProgress::slot_type& slot) 
    { 
    downloadTask_->onDownloadProgress(slot); 
    } 

    void runDownloadTask() { downloadTask_.submit() } 

private: 
    boost::shared_ptr<UpdaterDownloadTask> downloadTask_; 
}; 

Więc moje Updater musi mieć instancję UpdaterDownloadTask który jest zawsze wokół, który ma wystąpienie HTTPRequest, która ma wystąpienie HTTPResponse -Tylko dlatego, że mam do przekazania gniazda połączenie z Updater (publicznego API punkt odbioru) do HTTPResponse (gdzie należy sygnał).

wolałbym wdrożyć UpdaterDownloadTask::run() tak:

void run() 
{ 
    HTTPRequest request; 
    request.onDownloadProgress(slots_); 

#if 0 
    // The above is more or less equivalent to 
    BOOST_FOREACH(const DownloadProgress::slot_type& slot, slots_) 
    { 
     request.onDownloadProgress(slot); 
    } 
#endif 

    request.perform(); 
} 

będzie to mieć podobne skutki na poziomie HTTPRequest (tak nie muszą skonstruować httpResponse dopóki nie wykona żądanie) i ogólną markę dla lepszego przepływu danych z silną semantyką RAII. Mam wcześniej próbował definiując zmienną slots_ jako wektor:

std::vector<DownloadProgress::slot_type> slots_; 

Jeszcze mogę to tylko do pracy, jeśli zmusić zadzwonienie onDownloadProgress(boost::ref(slot));.

Czy ktoś zrobił to z powodzeniem lub miał dobrą sugestię, jak przechowywać i przesyłać dalej niż to, co robię?

Odpowiedz

2

Myślę, że przechowywanie gniazd w wektorze powinno działać poprawnie.Jeśli chcesz pozbyć się potrzeby boost::ref(...), możesz usunąć & z parametru onDownloadProgress (ponieważ slot_type można kopiować).

Alternatywnie, można mieć swój sygnał wewnątrz HTTPResponse ognia i kolei pożaru sygnał w HTTPRequest, robi, że można połączyć wszystkie szczeliny do sygnału w HTTPRequest, a następnie po utworzeniu HTTPResponse, łączysz się z odpowiedzią sygnał onDownloadProgress(request.signalname). Gdzie signalname jest sygnałem Twojego klienta.

pseudokod:

Request request; 
request.onProgress(myProgressBarCallback); 
    //calls: this.signal.connect(myProgressBarCallback); 
request.go(); 
    //calls: Response response; 
    // and: response.onProgress(this.signal); 

Mam nadzieję, że pomaga.

+0

Próbowałem wcześniej pewnych rzeczy z wektorem, ale mógł to być błąd z mojej strony. Myślę, że masz rację. –

Powiązane problemy