2011-11-02 10 views
7

Zastanawiam się, czy Boost.Format obsługuje przy użyciu bufor o ustalonej szerokości/wstępnie przydzielone jako wyjście zamiast dynamicznego bufora zarządzanego przez samą bibliotekę?Czy można użyć Boost.Format z wstępnie przydzielonym buforem?

To znaczy, zwykle chcesz zrobić:

boost::format myfmt("arg1: %1%/arg2: %2%"); 
// e.g.: 
cout << (myfmt % 3.14 % 42); 
// or 
string s = boost::str(myfmt % "hey!" % "there!"); 

więc Boost: Format lib automatycznie dbać o przydzielenie wystarczająco dużo miejsca i zarządzania „bufor wyjściowy” dla Ciebie.

Zastanawiałem się, czy istnieje jakikolwiek sposób, aby użyć predefine niedynamiczną bufor z Boost.Format, że jest coś takiego:

const size_t buf_sz = 512; 
char big_enough[buf_sz]; 
boost::format myfmt("arg1: %1%/arg2: %2%"); 
myfmt.attach_buffer(big_enough, buf_sz); 
myfmt % "hey!" % "there!" 
// big_enough buffer now contains the result string 

wiem, może po prostu przesiać przez przykłady i docs źródło, ale oprócz braku czasu atm. (i sama możliwość przegapienia czegoś) byłoby interesujące wiedzieć: Jeśli nie jest to możliwe, byłoby świetnie, gdyby ktoś mógł wyjaśnić, dlaczego (jeśli są/są konkretne problemy) - czy było to celowe? nie pasuje do interfejsu API? ...?

Nota prawna: To pytanie jest nie o wydajności!

+0

Co chcesz zdarzyć, gdy zabraknie miejsca? Dla stałego buffa użyłbym snprintf, ale to ja :) – nhed

+0

@nhed Jeśli nie pasuje, biblioteka może/mogłaby rzucić wyjątek lub po prostu przestać wypełniać bufor (podobnie jak [opcje] (http://www.boost.org/doc/libs/1_47_0/libs/format/doc/format.html#exceptions) już dostępne) –

+0

Nie jestem pewien, czy te wyjątki dotyczą bufora docelowego. – nhed

Odpowiedz

4

pomysłu

Patrząc na source wydaje można użyć własnego przydzielania, który jest następnie używany przez strumienia wewnętrznego (internal_streambuf_t) z boost::format. Czy to wystarczyłoby dla twojej sprawy?

Na przykład można użyć coś jak libstdC++ array_allocator

Niestety boost::format wykorzystuje również kilka std::vector które nie korzystają z niestandardowych przydzielania co może być problemem w Twoim przypadku?

Jak boost::format działa

zajrzałem do źródła boost::format i to jest, jak to działa (opisany poniżej jest str(), << połączeń albo str() lub wykorzystuje standardowy std::ostream rzeczy):

  • klasę formatowania przechowuje wszystkie argumenty i formatuj ciąg oddzielnie, czasami używając niestandardowego programu przydzielającego, czasami używając domyślnego przydziału
  • , gdy nazywa się to cr eates nowy std::string i sprawia, że ​​jest wystarczająco duży dla wyniku korzystania z niestandardowych przydzielania
  • to wówczas dołącza wszystkie argumenty i statycznych elementów ciągów z łańcucha formatu do ciągu wynikowego
  • wreszcie zwraca łańcuch wynik przez wartość

Ostateczny ciąg wyników nie jest zapisywany w klasie formatu, ale tworzony w razie potrzeby.

Więc nawet jeśli uda Ci się znaleźć położenie łańcucha wyników przy użyciu niestandardowego przydziału, jest on dostępny tylko po/podczas połączenia z str(). To powinno wyjaśnić, dlaczego nie jest możliwe: sformatowany wynik nigdy nie jest przechowywany w "buforze wyjściowym" w klasie.

Dlaczego to działa tak

Dlaczego zrobili to w ten sposób, że nie wiem. Myślę, że to dlatego, że możesz zbudować wynik tylko po poznaniu wszystkich argumentów, marnuje miejsce na zapisanie wyniku i prawdopodobnie potrzebujesz tylko wyniku tylko raz dla danej kombinacji format/argument. Zatem tworzenie go w razie potrzeby nie powoduje dodatkowej pracy, ponieważ zwykle str() jest wywoływane tylko raz.

Solutions

  • stworzyć jakiś otoki wokół str() lub << i skopiować wynik do swojej stałej buforze
  • Korzystanie a (przykład poniżej) stream_buffer do „strumienia” struny do bufora
  • Inherit klasy i dodaj własną funkcję str(), która przechowuje wynik w ustalonym buforze.

Możliwe rozwiązanie używając boost::iostreams (testowane):

#include <iostream> 
#include <boost/format.hpp> 
#include <boost/iostreams/stream.hpp> 

int main() 
{ 
    char buffer[100]; 

    boost::iostreams::stream<boost::iostreams::array_sink> 
     stream(buffer, sizeof(buffer)); 

    stream << (boost::format("arg1 = %1%") % 12.5); 
    stream << '\0'; // make sure buffer contains 0-terminated string 

    std::cout << buffer << std::endl;  
} 
+0

Przydatne informacje. Myślę, że niewielkim problemem z podzielnikami jest to, że mogą zgłaszać błędy tylko przez bad_alloc, prawda? –

+0

@Martin: Myślę, że masz rację. Ponadto zajrzałem do źródła formatu i uważam, że używanie alokatora jest trudne. Zaktualizowałem swoją odpowiedź na rzeczy, które znalazłem. – rve

+0

Dobra robota! Czy rozumiem cię poprawnie: Łańcuch wyjściowy jest ponownie budowany za każdym razem, gdy wywoływane jest '.str()'? –

Powiązane problemy