Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Tablica przechowująca wiele typów

Ostatnio zmodyfikowano 2017-04-02 22:08
Autor Wiadomość
Bielan
» 2017-04-02 20:28:40
Niestety nie otrzymasz takiego mechanizmu za darmo.

Zapis typów wbudowanych jest prosty: można go wykonać za pomocą zapisu binarnego lub pośrednio przez string.

Niestety typy definiowane przez użytkownika będą wymagały obsługi. Jeżeli chcesz zapisać na przykład jakiś typ użytkownika, który jest listą i ma tablicę wskaźników to po zapisaniu go i wczytaniu pozycje wskaźników będą nieprawidłowe ponieważ wczytane elementy będą gdzie indziej w pamięci.

Wszystkie dane, które można traktować jak POD możesz zapisać binarnie wszystko inne musisz obsłużyć.

Możesz próbować użyć czegoś gotowego np.
Frazy, które należy wpisać w wyszukiwarkę google:
P-159723
marcolo2307
Temat założony przez niniejszego użytkownika
» 2017-04-02 20:48:34
POD mi wystarczy, nie zamierzam tam trzymać naprawdę skomplikowanych klas, bardziej pojemniki na dane typu rozmiar okna, skala, kolor itd.

Ale w jaki sposób mam to wszystko przechować w jednym kontenerze? boost::any nie zapiszę do pliku, a void* nie usunę.
P-159727
Bielan
» 2017-04-02 20:56:16

Chcę zapisu także wbudowanych typów: int, bool itd. Do tego np. std::string


POD mi wystarczy, nie zamierzam tam trzymać naprawdę skomplikowanych klas

1.
std::string
 nie jest POD.

2. Poczytaj o: http://en.cppreference.com/w​/cpp/memory/shared_ptr​/get_deleter. Taki mechanizm wykorzystują inteligentne pointery.

3. Pamiętaj, że nie możesz wywołać delete na niczym co jest alokowane na stosie, czyli jak będziesz wrzucał na przemian struktury i wskaźniki do struktur to możesz mieć problem.
P-159728
mokrowski
» 2017-04-02 21:09:02
Próbujesz rozwiązywać problem XY. W dodatku zmieniasz wymagania co do tego czego potrzebujesz w trakcie. I to niestety w sposób istotny.
Usiądź zastanów się i powiedz czego dokładnie potrzebujesz. Najpierw (chociaż pobieżnie) zapoznaj się z tym:

http://xyproblem.info/
http://www.boost.org/doc/libs/1_63_0/doc/html/variant.html
http://www.boost.org/doc/libs/1_63_0/doc/html/any.html
http://www.boost.org/doc/libs/1_63_0/libs/serialization/doc/index.html
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
https://developers.google.com/protocol-buffers/?hl=en

Oczywiście to potencjalny wycinek tego czego możesz potrzebować. Wystarczy jednak byś mógł to nazwać precyzyjnie.
P-159730
Elaine
» 2017-04-02 21:38:49
boost::any nie zapiszę do pliku
Więc użyj tej samej techniki, której używa boost::any, tylko rozszerz ją o zapis do pliku i co tam jeszcze potrzebujesz:
C/C++
#include <iostream>
#include <map>
#include <memory>
#include <ostream>
#include <string>
#include <type_traits>
#include <utility>

template < typename T, typename = std::enable_if_t < std::is_standard_layout < T > { } >>
void save( std::ostream & stream, const T & thing )
{
    stream.write( reinterpret_cast < const char *>( std::addressof( thing ) ),
    sizeof( thing ) );
}

void save( std::ostream & stream, const std::string & string )
{
    const auto length = string.size();
    save( stream, length );
    stream.write( string.data(), static_cast < std::streamsize >( length ) );
}

struct erased_holder_base {
public:
    virtual ~erased_holder_base() = default;
    erased_holder_base( const erased_holder_base & ) = delete;
    erased_holder_base & operator =( const erased_holder_base & ) = delete;
   
    virtual void save( std::ostream & stream ) = 0;
protected:
    erased_holder_base() = default;
};

template < typename T >
class erased_holder final
    : public erased_holder_base
{
public:
    explicit erased_holder( T value );
   
    void save( std::ostream & stream ) override;
private:
    T value;
};

template < typename T >
erased_holder < T >::erased_holder( T value )
    : value( std::move( value ) )
{
}

template < typename T >
void erased_holder < T >::save( std::ostream & stream )
{
    ::save( stream, value );
}

int main()
{
    std::map < std::string, std::unique_ptr < erased_holder_base >> values;
    values.emplace( "foo", std::make_unique < erased_holder < int >>( 1 ) );
    values.emplace( "bar", std::make_unique < erased_holder < double >>( 2.0 ) );
    values.emplace( "qux", std::make_unique < erased_holder < std::string >>( "żółć" ) );
   
    for( auto && value: values ) {
        value.second->save( std::cout );
    }
}


>> ./Release/blahblah | hd
00000000  00 00 00 00 00 00 00 40  01 00 00 00 08 00 00 00  |.......@........|
00000010  00 00 00 00 c5 bc c3 b3  c5 82 c4 87              |............|
0000001c
P-159737
Elaine
» 2017-04-02 21:56:04
W Booście jest też biblioteka do type erasure, która tutaj się świetnie nadaje:
C/C++
#include <iostream>
#include <map>
#include <memory>
#include <ostream>
#include <string>
#include <type_traits>
#include <boost/type_erasure/any.hpp>
namespace te = boost::type_erasure;

template < typename T, typename = std::enable_if_t < std::is_standard_layout < T > { } >>
void save( std::ostream & stream, const T & thing )
{
    stream.write( reinterpret_cast < const char *>( std::addressof( thing ) ),
    sizeof( thing ) );
}

void save( std::ostream & stream, const std::string & string )
{
    const auto length = string.size();
    save( stream, length );
    stream.write( string.data(), static_cast < std::streamsize >( length ) );
}

template < typename T = te::_self >
struct saveable {
    static void apply( std::ostream & stream, const T & thing )
    {
        save( stream, thing );
    }
};

namespace boost {
    namespace type_erasure {
       
        template < typename T, typename Base >
        struct concept_interface < saveable < T >, Base, T >
            : Base
        {
            void save( std::ostream & stream ) const
            {
                return call( saveable < T > { }, stream, * this );
            }
        };
       
    }
}

using holder_type = te::any < boost::mpl::vector < te::destructible <>, saveable <>>>;

int main()
{
    std::map < std::string, holder_type > values;
    values.emplace( "foo", 1 );
    values.emplace( "bar", 2.0 );
    values.emplace( "qux", std::string( "żółć" ) );
   
    for( auto && value: values ) {
        value.second.save( std::cout );
    }
}
P-159740
marcolo2307
Temat założony przez niniejszego użytkownika
» 2017-04-02 22:08:09
Dzięki wszystkim za pomoc.

Alueril, nie jestem w stanie zrozumieć Twojego kodu, muszę poczytać o tych wszystkich klasach.

Postaram się jak najszybciej wykorzystać wasze materiały, ale jako iż jutro jest poniedziałek to najpierw muszę zająć się szkołą (btw. tylko u mnie przedmioty zawodowe polegają na przepisywaniu slajdów/monologu nauczyciela do zeszytu lub "praktycznym" liczeniu w systemach siódemkowych i czternastkowych?).



Edit:

Alueril, nie skorzystam z Twojego rozwiązania, jest dla mnie zbyt skomplikowane, mój kompilator nawet go nie akceptuje. Tak samo wolę się nie bawić w to co mi podesłałeś Bielan. Spróbuję to zrozumieć, ale obecnie chcę czegoś, co będzie działało i z czego będę mógł skorzystać wiedząc jak to działa.



Pozostaje mi chyba po prostu dziedziczyć po wspólnej klasie i starać się ograniczać liczbę typów, z których będę korzystać, tak będzie najprościej. Jeszcze raz dzięki za pomoc, temat pozostawiam otwarty, może ktoś jeszcze coś wymyśli.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W sumie nie wiem czemu nie skorzystałem z tego wcześniej... W każdym razie zdecydowałem się na trzymanie danych POD w char*. Niestety stringi odpadają, trzeba korzystać ze zwykłych char*, ale w przyszłości po prostu dodam dla nich specjalną funkcję w stylu "addString".

Zamykam temat.
P-159741
1 « 2 »
Poprzednia strona Strona 2 z 2