PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Alternativen zu BOOST:ANY



ufosworld
02-08-2007, 09:33
Nachdem ich das Problem mit den Strings / Char speichern mit dem Datentyp BOOST:ANY nicht zum laufen bekomme.

( Integer und Double speichert er schön ab und kann diese auch an ein anderes Modul übergeben, Strings wirft er bei Übergabe ins nächste Modul einfach weg, Char Ptr liesst er falsche Speicherstellen aus)

Suche ich Alternativen zu BOOST.

Hab bisher folgende gefunden:

cdiggins::any
Pablo Aguilarg any

hat jemand bereits Erfahrungen mit den Alternativen?
Vor allem lauffähige Codebeispiele?

locus vivendi
02-08-2007, 10:34
Nachdem ich das Problem mit den Strings / Char speichern mit dem Datentyp BOOST:ANY nicht zum laufen bekomme.

( Integer und Double speichert er schön ab und kann diese auch an ein anderes Modul übergeben, Strings wirft er bei Übergabe ins nächste Modul einfach weg, Char Ptr liesst er falsche Speicherstellen aus)

Suche ich Alternativen zu BOOST.
Mit erscheint es unwahrscheinlich das Boost.Any die Probleme verursacht. Ich glaube eher das du Fehler in deinem Code hast.

ufosworld
03-08-2007, 09:22
Hier mal der Code mit unten angefügter Ausgabe der das Problem teilweise schon verdeutlicht:


#include <iostream>
#include <stdio.h>
#include <list>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::list<boost::any> many;
many values;


using namespace std;



void append_char_ptr(many & values, const char * value)
{
values.push_back(value);
}

void append_string(many & values, const std::string & value)
{
values.push_back(value);
}

void append_any(many & values, const boost::any & value)
{
values.push_back(value);
}


bool is_empty(const boost::any & operand)
{
return operand.empty();
}

bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}

bool is_double(const boost::any & operand)
{
return operand.type() == typeid(double);
}

bool is_char_ptr(const boost::any & operand)
{
try
{
any_cast<const char *>(operand);
return true;
}
catch(const boost::bad_any_cast &)
{
return false;
}
}

bool is_string(const boost::any & operand)
{
return any_cast<std::string>(&operand);
}

void count_all(many & values, std::ostream & out)
{
out << "#empty == "
<< std::count_if(values.begin(), values.end(), is_empty) << std::endl;
out << "#int == "
<< std::count_if(values.begin(), values.end(), is_int) << std::endl;
out << "#double == "
<< std::count_if(values.begin(), values.end(), is_double) << std::endl;
out << "#const char * == "
<< std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl;
out << "#string == "
<< std::count_if(values.begin(), values.end(), is_string) << std::endl;
}


void print_all(many & values)
{

many::iterator it = values.begin(); //erzeuge Iterator it und setze auf values.begin()
many::iterator endit = values.end(); //erzeuge Iterator endIt und setzte auf values.end()



// durchlaufe die gesamte Liste und gib alle Daten aus
for (; it != endit; ++it)
{

if (is_int(*it))
std::cout << "Int: "<<any_cast<int>(*it)<<std::endl;
else if (is_string(*it))
std::cout << "String: "<<any_cast<std::string>(*it)<<std::endl;
else if (is_char_ptr(*it))
std::cout << "Char_Ptr: "<<any_cast<const char*>(*it)<<std::endl;
else if (is_empty(*it))
std::cout << "Empty: "<<std::endl;
else if (is_double(*it))
std::cout << "Double: " <<any_cast<double>(*it) <<std::endl;
}
std::cout<< std::endl;

}




int main()
{

append_any(values,7);
append_any(values,4.3);
append_any(values,'a'); // Wo taucht dieser Wert auf?
append_string(values,"test");
append_char_ptr(values,"haha32");
// append_any(values,"test32"); // wie kann ich append_any so umbauen, das dies geht?


count_all(values, cout);

std::cout << std::endl;

print_all(values);


return 0;
}


/* Ausgabe:

#empty == 0
#int == 1
#double == 1
#const char * == 1
#string == 1

Int: 7
Double: 4.3
String: test
Char_Ptr: haha32

*/




Wie das Beispiel aufzeigt, werden die String / CHar_Ptr Werte nur hinzugefügt, wenn ich die append_string bzw append__char_ptr Funktionen benutze.

Ausserdem unterschlägt er das 'a'. Wo is das?

Ich möchte aber das die append_any Funktion diese Werte ebenfalls verarbeiten kann.

z.b.
append_any(values,"Stringwert")
append_any(values,'w');
append_any(values,'m');
usw...



Wie ist die append_any Funktion abzuändern, sodass ich auch String /Chars Char_Ptr Werte hinzufügen kann, ohne vorab zu wissen um welchen Datentyp es sich bei dem Wert handelt... den dies ist ja dann bei append_string schon vorausgesetzt zu wissen das es ein String ist...

Sinn und Zweck des Any Typs soll es ja sein, sich eben nicht Sorgen machen zu müssen um welchen Datentyp es sich handelt... sondern jeden beliebigen Wert erst einmal abzuspeichern um dann mittels der is_??? Funktionen herauszufinden was für ein VariablenTyp an der Speicherstelle steht... um dann entsprechende Berechnungen anstellen zu können.

mfg UFO

locus vivendi
03-08-2007, 11:34
Wie das Beispiel aufzeigt, werden die String / CHar_Ptr Werte nur hinzugefügt, wenn ich die append_string bzw append__char_ptr Funktionen benutze
Hier liegt ein Missverständnis bei dir vor. Ein String wie "haha32" hat *nicht* den Type char* oder char const*, sondern es ist ein Array. Und wie in deinem letzten Thread um Boost.Any bereits geschrieben, kannst du Arrays nicht mit Boost.Any speichern. Du könntest also z.B. append_any(values, static_cast<char const*>("haha32") aufrufen. Und dann würde der Zeiger auch gespeichert werden. Oder du könntest append_any überladen: "void append_any(many& values, char const* str);" Diese Signatur ist beim wählen des aufzurufenden Overloads ein bevorzugter Treffer im Vergleich mit boost::any, deshalb könntest du damit auf den Cast beim Aufruf verzichten. Beide Wege habe ich dir mal gezeigt, in dem Code unten.

Dann möchte ich auch noch mal zu bedenken geben, das beim Speichern von Zeigern auf Chars immer das Problem da ist, zu entscheiden, ob der Zeiger einen String bezeichnen soll. Sprich: Wissen alle Teile die mit den Any-Werten umgehen ob ein char const* als String oder als Zeiger auf ein *einzelnes* Zeichen zu verstehen ist?
Wenn dies immer geklärt ist, spricht nichts dagegen Zeiger zu speichern. Wenn dies nicht immer klar ist, dann würde ich dazu raten nur std::strings oder Ähnliches zu speichern, und keine char const*.


Ausserdem unterschlägt er das 'a'. Wo is das?
Es ist in der Liste. Du testest nur nicht ob darin char-Werte enthalten sind. Test + Ausgabe dafür habe ich im Code unten eingebaut.


Wie ist die append_any Funktion abzuändern, sodass ich auch String /Chars Char_Ptr Werte hinzufügen kann, ohne vorab zu wissen um welchen Datentyp es sich bei dem Wert handelt... den dies ist ja dann bei append_string schon vorausgesetzt zu wissen das es ein String ist...
Ich glaube, hier verwechselst du auch etwas. Beim erstmaligen Speichern eines Wertes in ein Boost.Any hinein, ist die Forderung, dies sollte auch ohne Kenntnis des Typs gehen sinnlos. Denn an dieser Stelle ist ja garantiert das du den Typ kennst (ohne diese Information könnte der Boost.Any Konstruktor gar nicht aufgerufen werden).

Hier nun der Code. Es ist dein Beispiel von mir etwas abgeändert.

#include <iostream>
#include <stdio.h>
#include <list>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::list<boost::any> many;
many values;


using namespace std;



void append_char_ptr(many & values, const char * value)
{
values.push_back(value);
}

void append_string(many & values, const std::string & value)
{
values.push_back(value);
}

void append_any(many & values, const boost::any & value)
{
values.push_back(value);
}

void append_any(many& values, char const* str)
{
values.push_back(str);
}

bool is_empty(const boost::any & operand)
{
return operand.empty();
}

bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}

bool is_double(const boost::any & operand)
{
return operand.type() == typeid(double);
}

bool is_char_ptr(const boost::any & operand)
{
try
{
any_cast<const char *>(operand);
return true;
}
catch(const boost::bad_any_cast &)
{
return false;
}
}

bool is_string(const boost::any & operand)
{
return any_cast<std::string>(&operand);
}

bool is_char(boost::any const& operand)
{
return operand.type() == typeid(char);
}

void count_all(many & values, std::ostream & out)
{
out << "#empty == "
<< std::count_if(values.begin(), values.end(), is_empty) << std::endl;
out << "#int == "
<< std::count_if(values.begin(), values.end(), is_int) << std::endl;
out << "#double == "
<< std::count_if(values.begin(), values.end(), is_double) << std::endl;
out << "#const char * == "
<< std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl;
out << "#string == "
<< std::count_if(values.begin(), values.end(), is_string) << std::endl;
out << "#char == " << std::count_if(values.begin(), values.end(), is_char) << '\n';
}


void print_all(many & values)
{

many::iterator it = values.begin(); //erzeuge Iterator it und setze auf values.begin()
many::iterator endit = values.end(); //erzeuge Iterator endIt und setzte auf values.end()



// durchlaufe die gesamte Liste und gib alle Daten aus
for (; it != endit; ++it)
{

if (is_int(*it))
std::cout << "Int: "<<any_cast<int>(*it)<<std::endl;
else if (is_string(*it))
std::cout << "String: "<<any_cast<std::string>(*it)<<std::endl;
else if (is_char_ptr(*it))
std::cout << "Char_Ptr: "<<any_cast<const char*>(*it)<<std::endl;
else if (is_empty(*it))
std::cout << "Empty: "<<std::endl;
else if (is_double(*it))
std::cout << "Double: " <<any_cast<double>(*it) <<std::endl;
else if(is_char(*it) )
{
std::cout << "Char: " << any_cast<char>(*it) << '\n';
}
}
std::cout<< std::endl;

}




int main()
{

append_any(values,7);
append_any(values,4.3);
append_any(values,'a');
append_string(values,"test");
append_char_ptr(values,"haha32");
append_any(values, static_cast<char const*>("test32") );
append_any(values, "xyz"); // Overload von append_any beachten

std::cout << "\nAnzahl von Elementen insgesamt: " << values.size() << '\n';
count_all(values, cout);

std::cout << std::endl;

print_all(values);


return 0;
}

ufosworld
08-08-2007, 14:13
Ok danke erstmal.... läuft ja schon ganz gut...

Leider habe ich noch folgende Probleme...

Strings mag er jetzt gar nicht mehr.




char * cstr;
string str ("Tester");

for (int a = 1; a<=5; a++)
{
b= b + 1.11; //Variablen Double Wert

str = "Tester" ;
str = str+(char)(65+a);
cstr = new char [str.size()+1];
strcpy (cstr, str.c_str()); // ist nötig, da bei Stringübergabe fehler... => Char*

append_any(values, cstr); // Overload von append_any beachten (vales, str)

append_any(values,10.001+b); // Double Werte :klappt
append_any(values,100+a); // Integer Werte :klappt
append_any(values,1); // eine 1 hinzufügen (Integer)
// append_any(values,0110); //FEHLER!! binäre 0110 wird als Oktal in 72 umgewandelt
// append_any(values,065900); //FEHLER!! er erkennt die 065 als Oktal, aber 9 ist keine Oktalzahl
// append_any(values,9876543210); //FEHLER!! Integer too large for long type
// append_any(values,0); //FEHLER!! sobald nur 0 geschrieben werden soll schliesst er den Handle
// append_nothing(values); // Empty Werte :klappt
}


Wie kann man die Append Funktion so umbauen, so das er nicht mehr den Fehler produziert... und die Strings als Strings abspeichert... und nicht als Char Ptr

Wie kann ich bool-Werte hinzufügen (also 1 oder 0)
(Nachtrag: habe gerade Funktion geschrieben, die mir das append_any überlädt... diese Funktion heisst
bool is_bool(.....). sobald ich dann append_any(values,true); mache... gehts...
wenn ich append_any(values,false); gehts nicht... er schliesst den Handle... anscheinend vom Modul in dem das ganze läuft... ^^)

Wie kann ich Binärewerte hinzufügen ohne das er diese als Oktalwerte interpretiert (z.b. 0110)
ohne die Werte jeweils mit "...." anzugeben und somit wieder mit Cast in Zahlen umzumodeln

anda_skoa
08-08-2007, 15:32
// append_any(values,0110); //FEHLER!! binäre 0110 wird als Oktal in 72 umgewandelt
// append_any(values,065900); //FEHLER!! er erkennt die 065 als Oktal, aber 9 ist keine Oktalzahl


Kein Fehler, eine Null beginnt immer ein Oktal Literal, so wie 0x immer ein Hex Literal beginnt.





// append_any(values,9876543210); //FEHLER!! Integer too large for long type


Auch kein Fehler, ein long ist auf 32 Bit Plattformen praktisch immer 32 Bit lang, d.h. Wertebereich zwischen -2 Mrd und +2Mrd.
Wenn du explizit einen 64 Bit Wertebreich brauchst, kannst du zB int64_t benutzen.





// append_any(values,0); //FEHLER!! sobald nur 0 geschrieben werden soll schliesst er den Handle


Vermutlich eine Mehrdeutigkeit von 0, wird vielleicht als 0 Pointer interpretiert.

Du könntest dir die const char* Werte schenken und immer std::string benutzen, d.h. etwaige const char* zuerst in einen string verfrachten und dann anhängen



const char* text = "foo";

std::string textAsString(text);

append_string(values, textAsString);




Wie kann ich Binärewerte hinzufügen ohne das er diese als Oktalwerte interpretiert (z.b. 0110)

Hexadezimalschreibweise. In C, C++ und syntaktisch ähnlichen Sprachen praktisch die Art und Weise wie man bestimmte Bitmuster im Code festlegt.

Ciao,
_

locus vivendi
08-08-2007, 15:46
Wie kann man die Append Funktion so umbauen, so das er nicht mehr den Fehler produziert... und die Strings als Strings abspeichert... und nicht als Char Ptr
Es funktioniert immer auf die gleiche Art. Der Wert wird von Boost.Any in dem Typ gespeichert, der an Boost.Any übergeben wird (genau genommen handelt es sich um den statischen Typ, nicht um den dynamischen). Es ist keinerlei "Magie" am Werk die irgendwie versucht einen bestimmten Typ zu erkennen oder anzupassen.
Wenn du also z.B. einen std::string speichern möchtest, dann übergebe auch einen std::string: 'boost::any any1(std::string("ladida") )'


Wie kann ich bool-Werte hinzufügen (also 1 oder 0)
(Nachtrag: habe gerade Funktion geschrieben, die mir das append_any überlädt... diese Funktion heisst
bool is_bool(.....). sobald ich dann append_any(values,true); mache... gehts...
wenn ich append_any(values,false); gehts nicht... er schliesst den Handle... anscheinend vom Modul in dem das ganze läuft... ^^)
Was für ein Handle? Irgendwie verstehe ich nicht ganz wovon dieser Absatz handelt.


Wie kann ich Binärewerte hinzufügen ohne das er diese als Oktalwerte interpretiert (z.b. 0110)
ohne die Werte jeweils mit "...." anzugeben und somit wieder mit Cast in Zahlen umzumodeln
Willst du schon ein Integer speichern, bloß so, 00101..., hinschreiben, oder willst du auch irgendeinen speziellen "Bit-Typ" speichern?

ufosworld
14-08-2007, 14:05
So nachdem ich jetzt ein paar Datensätze in der Liste stehen habe, wollte ich diese Datensätze ändern.

Da es aber bei std::list keine fertige Methode gibt zum ändern eines Datensatzes (habe keine gefunden),
muss ich wohl den Wert auslesen, abändern, den ausgelesenen Wert in der Liste löschen , und den abgeänderten Wert in der Liste speichern.

(falls es doch eine Funktion geben sollte.. bitte schreibt mir...)

hab also folgende Funktion gestrickt...



Aufruf:
edit_int(8,30,values); //nehmen wir an an Position 8 steht ein Integer Wert



Funktion:


void edit_int(int pos, int wert, many & values)
{
int a;
int zahl=0;
many::iterator it_start = values.begin(); //erzeuge Iterator start und ruck und setze auf values.begin()
many::iterator it_ruck; // Hier keine Initialisierung, sonst stürzt er ab... wieso ??


if (values.size() < pos)
{
cout << "Datensatz Nummer " << pos << " existiert nicht! Abbruch von Edit\n";
}
else
{
for (a=1; a<pos; a++)
{
it_start++;
}

zahl = any_cast<int>(*it_start); //z.b. 101 wurde ausgelesen
cout <<"Edit Daten: " << zahl <<"\n"; // Ausgabe: Edit Daten: 101
zahl = zahl + wert; // 131 = 101 + 30;

cout << "Neuer Wert: " <<zahl <<endl; //Neuer Wert: 131

it_ruck = values.erase(it_start); // Lösche 101 an Position 8
it_ruck = values.insert(it_ruck,zahl); // funktioniert (schreibt 131
// an Pos 8) aber erzeugt
// Speicherschutzverletzung...
}

}


kann mir mal jemand sagen was mit dem Code nicht stimmt...

mfg UFO

locus vivendi
14-08-2007, 14:44
So nachdem ich jetzt ein paar Datensätze in der Liste stehen habe, wollte ich diese Datensätze ändern.

Da es aber bei std::list keine fertige Methode gibt zum ändern eines Datensatzes (habe keine gefunden),
muss ich wohl den Wert auslesen, abändern, den ausgelesenen Wert in der Liste löschen , und den abgeänderten Wert in der Liste speichern.
Wenn du einen Iterator hast der auf ein bestimmtes Element zeigt, dann kannst du das Element direkt über diesen Iterator ändern.

Für irgendwelche Segmentation Faults oder ähnliches wäre ich auf ein vollständiges übersetzbares Beispiel angewiesen um etwas sagen zu können.

Warum arbeitest du eigentlich mit 1-basierten Indizes, statt mit 0-basierten? Nicht das das von vornherein falsch wäre, aber letzteres ist in C und C++ konventioneller.

ufosworld
16-08-2007, 09:25
Wenn du einen Iterator hast der auf ein bestimmtes Element zeigt, dann kannst du das Element direkt über diesen Iterator ändern.


wie ginge das? Codebeispiel... weil bei den Methoden zu list finde ich leider nichts... wie ich über Iterator einen Datensatz ändern kann.



Warum arbeitest du eigentlich mit 1-basierten Indizes, statt mit 0-basierten? Nicht das das von vornherein falsch wäre, aber letzteres ist in C und C++ konventioneller.

werde das mal ändern... (du meinst weil die For-Schleife bei 1 startet und nicht bei 0...).

locus vivendi
16-08-2007, 11:00
Zitat von locus vivendi Beitrag anzeigen
Wenn du einen Iterator hast der auf ein bestimmtes Element zeigt, dann kannst du das Element direkt über diesen Iterator ändern.wie ginge das? Codebeispiel... weil bei den Methoden zu list finde ich leider nichts... wie ich über Iterator einen Datensatz ändern kann.
Jeder Standard-Container bietet doch Iteratoren an mit denen man auf dessen Elemente zugreifen kann und den Container durchlaufen kann. Der Elementzugriff funktioniert dabei ähnlich wie bei einem Pointer über die * und -> Operatoren. Beispiel: Wenn "it" ein Iterator auf ein Listenelement (oder std::vector Element, oder std::deque Element oder ...-Element) ist und "x" ein Objekt vom Typ der Listenelemente, dann kannst du mit "*it = x" dem entsprechedem Listenelement den Wert x zuweisen.

Zum Beispiel könntest du sämtliche Elemente eines Containers so ändern:


std::list<boost::any> many;
....
boost::any x = std::string("abc");
for(std::list<boost::any>::iterator cur = many.begin(); cur != many.end(); ++cur)
{
*cur = x;
}

(Das ist nur ein Beispiel, man würde das so nicht wirklich schreiben)

Das ist alles aber auch ziemlich simple C++ "Brot und Butter" Anwendung. Hast du irgendein C++ Lehrbuch? Das wäre vielleicht ganz hilfreich. Alternativ kannst du vielleicht mal in die C++-Annotations reinschauen:
http://www.icce.rug.nl/documents/cpp.shtml
Besonders Kapitel 12 "Abstract Containers" und 17 "Standard Template Library".

ufosworld
22-08-2007, 13:29
mhh ganz komisch...

ich hab mal das mit dem *it = 18; ausprobiert... siehe Quellecode:



void edit_int(int pos, int wert, many & values)
{
int a;


many::iterator it_start = values.begin(); //erzeuge Iterator start und setze auf values.begin()



if (values.size() < pos)
{
cout << "Datensatz Nummer " << pos << " existiert nicht! Abbruch von Edit\n";
}
else
{

for (a=1; a<pos; a++)
{
it_start++;
}



// nun soll er einen Wert hinzufügen... es geht beides, aber bei beiden eine Speicherschutzverletzung jeweils am Ende des Programms...
//values.insert(it_start,13); // Speicherschutzverletzung, aber geht
*it_start = 18; // Speicherschutzverletzung, aber geht


}

}



der many& values typ sieht so aus...


typedef std::list<boost::any> many;
es werden auch daten reingespeichert und ausgegeben, aber sobald ich
Wert einfüge mit values.insert dann kommt eine Speicherschutzverletzung...

Erstellen der Liste in einem anderen Modul gibt keine Probleme.
Auch das Feld das ich editir ist ein Integer.

locus vivendi
23-08-2007, 12:40
es werden auch daten reingespeichert und ausgegeben, aber sobald ich
Wert einfüge mit values.insert dann kommt eine Speicherschutzverletzung...
Wie ich schon schrieb: Ohne ein vollständiges Beispiel kann ich den Grund dafür nicht finden. Der Code-Schnippsel den du gezeigt hast ist nicht von vornherein inkorrekt.