Uživatelské nástroje

Nástroje pro tento web


cpp_tips

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revizePředchozí verze
Následující verze
Předchozí verze
cpp_tips [2016/04/25 16:53] – [struct na/z string] djbuldogcpp_tips [2025/08/28 10:09] (aktuální) – upraveno mimo DokuWiki 127.0.0.1
Řádek 1: Řádek 1:
 ====== Tipy & triky C++ ====== ====== Tipy & triky C++ ======
  
-===== char* do istringstrem =====+===== char* na istringstrem (bez kopírování) =====
  
  
Řádek 21: Řádek 21:
  
   * ověřil jsem to zavoláním free na mybuff (kód se musí upravit na dynamickou alokaci mybuf)   * ověřil jsem to zavoláním free na mybuff (kód se musí upravit na dynamickou alokaci mybuf)
 +  * metoda [[http://www.cplusplus.com/reference/streambuf/streambuf/pubsetbuf/|pubsetbuf]] je nabízena třídou streambuf, ale implementována až v strbuf nebo filebuf (takže v streambuf nedělá vlastně nic)
 +
 +===== char* do vector<char> =====
 +
 +<code cpp>
 +char arr[] = "abcd";
 +vector<char> buff;
 +buf->insert(buf->end(), arr, arr + strlen(abcd);
 +</code>
 +
 +===== stringstream na cout/string =====
 +
 +  * na příkladu
 +
 +<file cpp stringstream_test.cpp>
 +#include <iostream>
 +
 +using namespace std;
 +
 +int main() {
 +
 +  stringstream ss("SS");
 +  ostringstream os("OS");
 +  istringstream is("IS");
 +
 +  ss.get();
 +  cout << "1:" << ss << endl;
 +  cout << "2:" << ss.str() << endl;
 +  cout << "3:" << ss.rdbuf() << endl;
 +  cout << "4:" << ss.rdbuf()->str() << endl;
 +
 +  is.get();
 +  cout << "1:" << is << endl;
 +  cout << "2:" << is.str() << endl;
 +  cout << "3:" << is.rdbuf() << endl;
 +  cout << "4:" << is.rdbuf()->str() << endl;
 +
 +  //os.get();  // cannot be called on ostringstream
 +  cout << "1:" << os << endl;
 +  cout << "2:" << os.str() << endl;
 +  //cout << "3:" << os.rdbuf() << endl;
 +  cout << "4:" << os.rdbuf()->str() << endl;
 +
 +  cout << "---" << endl;
 +
 +  stringstream ss2;
 +  ostringstream os2("OS");
 +  istringstream is2("IS");
 +
 +  char my1[]="SS2";
 +  char my2[]="OS2";
 +  char my3[]="IS2";
 +
 +  ss2.rdbuf()->pubsetbuf(my1,3);
 +  os2.rdbuf()->pubsetbuf(my2,3);
 +  is2.rdbuf()->pubsetbuf(my3,3);
 +
 +  ss2.get();
 +  cout << "1:" << ss2 << endl;
 +  cout << "2:" << ss2.str() << endl;
 +  cout << "3:" << ss2.rdbuf() << endl;
 +  cout << "4:" << ss2.rdbuf()->str() << endl;
 +   
 +  is2.get();
 +  cout << "1:" << is2 << endl;
 +  cout << "2:" << is2.str() << endl;
 +  cout << "3:" << is2.rdbuf() << endl;
 +  cout << "4:" << is2.rdbuf()->str() << endl;
 +
 +  //os2.get(); // cannot be called on ostringstream
 +  cout << "1:" << os2 << endl;
 +  cout << "2:" << os2.str() << endl;
 +  //cout << "3:" << os.rdbuf() << endl;
 +  cout << "4:" << os2.rdbuf()->str() << endl;
 +
 +}
 +</file>
 +
 +  * spuštění vypíše
 +
 +<code>
 +1:0x7fff38741978
 +2:SS
 +3:S
 +4:SS
 +1:0x7fff38741c50
 +2:IS
 +3:S
 +4:IS
 +1:0x7fff38741f18
 +2:OS
 +4:OS
 +---
 +1:0x7fff38741808
 +2:SS2
 +3:S2
 +4:SS2
 +1:0x7fff38741ae0
 +2:
 +3:S2
 +4:
 +1:0x7fff38741db8
 +2:OS2
 +4:OS2
 +</code>
 +
 +  * všimni si, že přečtení znaku z ''istringstream'' způsobí, že rdbuf nevypíše všechny znaky
 +  * řeší se to přenastavením ukazatele a preventivním vymazáním flagů (například EOF flag)
 +
 +<code cpp>
 +is.clear();
 +is.seekg(0);
 +</code>
 +
 +  * dále, po nastavení bufferu přes ''pubsetbuf'' nějak nefunguje výpis z ''istringstream''
 +  * na příčinu jsem zatím nepřišel, ale řešení je použít ''stringstream''
  
 ===== Default parametry metody/funkce ===== ===== Default parametry metody/funkce =====
Řádek 95: Řádek 211:
 </code> </code>
  
-===== Převod struct na/z string =====+===== Převod struct na/z string (serializace) =====
  
   * struktura je v C++ ve skutečnosti třída, která má všechny položky public (žádný rozdíl mezi nimi není)   * struktura je v C++ ve skutečnosti třída, která má všechny položky public (žádný rozdíl mezi nimi není)
   * v C se struktura dala krásně využít pro parsování pole znaků, například hlavičky paketu   * v C se struktura dala krásně využít pro parsování pole znaků, například hlavičky paketu
   * v C++ lze samozřejmě používat stejným způsobem, ale jak by pro tento úkol šlo použít nové vlastnosti C++?   * v C++ lze samozřejmě používat stejným způsobem, ale jak by pro tento úkol šlo použít nové vlastnosti C++?
-  * + 
 +  * pokud struktura obsahuje pouze základní datové typy,  
 +    * lze strukturu převést na string zápisem do proudu stringstream po přetypování na pole znaků: 
 + 
 +<code cpp> 
 +stringstream out(stringstream::out|stringstream::binary) 
 +out.write((char *) &acc, sizeof(struct MyRecord)); 
 +</code> 
 + 
 +  * pokud obsahuje i objekty, jako například string, 
 +    * musí se zapsat po jednotlivých typech: 
 + 
 +<code cpp> 
 +.. 
 +out.write( rec.location.c_str(), rec.location.size() ); // string 
 +out.write( (char*) & rec.account_num, sizeof( rec.account_num ) ); // int 
 +.. 
 +</code> 
 + 
 +  * čtení probíhá obdobně... voláním funkce read 
 + 
 +===== Mapování struct do vector<char> ===== 
 + 
 +<code cpp> 
 +vector<char> v(sizeof(mystruct)); 
 +mystruct *s = reinterpret_cast<mystruct*>(v.data()); 
 +</code> 
 + 
 +===== Velikost struktury s polem znaků ===== 
 + 
 +  * platí v C/C++ 
 +  * jak velká je tato struktura? 
 +<code c> 
 +struct mystruct { 
 +  char data[]; 
 +
 +</code> 
 +   * sizeof hlasí 0B :) 
 +   * pokud ji chceme započítat, musíme napsat alespoň 
 +<code c> 
 +struct mystruct { 
 +  char data[1]; 
 +
 +</code> 
 + 
 +===== Private Hader file ===== 
 + 
 +  * třídy se typicky deklarují v hlavičkovém souboru 
 +  * třída má někdy privátní položku speciálního datového typu, který vyžaduje vložit speciální hlavičkový soubor 
 +  * pokud třídu využíváme v jiné třídě, zbytečně vkládáme další a další hlavičkové soubory 
 +  * přitom nás privátní položky jiné třídy vůbec nezajímají, jelikož je stejně nemůžeme používat 
 +  * vzniká tak potřeba tzv privátních a veřejných hlavičkových souborů 
 +  * další využití je pro skrytí vnitřní implementace třídy 
 + 
 +  * řešení s jedním hlavičkovým 
 +  * do hlavičkového přidáme podmínky.. 
 + 
 +<code cpp> 
 +#ifdef CONF_IMPL 
 +#include <libxml/xmlmemory.h> 
 +#include <libxml/parser.h> 
 +#endif 
 + 
 +.. 
 + 
 +class Conf { 
 + 
 +    private: 
 +        .. 
 +#ifdef ADSCONF_IMPL 
 +        void parsePref(xmlNodePtr cur); 
 +        void parseMet(xmlNodePtr cur); 
 +        void parseCfg(xmlNodePtr cur); 
 +#endif 
 +        .. 
 +     
 +    public: 
 +        Conf(); 
 +
 +</code> 
 + 
 +   * do zdrojového kódu, kde třídu implementujeme, přidáme ''#define CONF_IMPL'' 
 + 
 +===== Memory leak bez virtuálního destruktoru ===== 
 + 
 +  * pokud se z třídy dědí, měla by mít virtuální destruktor 
 +  * memory leak příklad: 
 +<code cpp> 
 +class Interface 
 +
 +   virtual void doSomething(void) = 0; 
 +}; 
 + 
 +class Derived : public Interface 
 +
 +   Derived(void); 
 +   ~Derived(void)  
 +   { 
 +      // Do some important cleanup... 
 +   } 
 +}; 
 + 
 +void myFunc(void) 
 +
 +   Interface* p = new Derived(); 
 +   // The behaviour of the next line is undefined. It probably  
 +   // calls Interface::~Interface, not Derived::~Derived 
 +   delete p;  
 +
 +</code> 
 + 
 +  * je to zajímavé, protože ve třídě nemusí být vůbec dynamická alokace. Stačí, aby měla jako member nějaký objekt, třeba string, a bez zavolaní správného destruktoru nedojde k dealokaci 
 +  * řešení je přidat virtuální destruktor do Base třídy, stačí takto: 
 +<code cpp> 
 +virtual ~Interface() {} 
 +</code>  
 + 
 + 
 +===== Soubor do paměti ===== 
 + 
 +<code c++> 
 +  ifstream sfile(filepath.c_str()); 
 +  if (!sfile) { 
 +      LogMsg(MSGERR, "Cannot open file %s for packing\n", filepath.c_str()); 
 +      flen = 0; 
 +  } else { 
 + 
 +      // checking file size... is getFileSize() better? 
 +      sfile.seekg(0, ios::end); 
 +      flen = sfile.tellg(); 
 +      sfile.seekg(0,ios::beg); 
 + 
 +      vector<char> fcxt(flen); 
 +      sfile.read(&fcxt[0], flen); 
 + 
 +      sfile.close(); 
 +  } 
 +</code> 
 + 
 +===== Paměť do souboru ===== 
 + 
 +<code c++> 
 +  ofstream f; 
 + 
 +  f.open(filepath.c_str()); 
 +  if (!f.is_open()) { 
 +      LogMsg(MSGERR, "Cannot create file for service %s\n", name.c_str()); 
 +      return 7; 
 +  } 
 + 
 +  f.write(v.data(), v.size()); 
 +  f << flush; // force to create empty file 
 +  f.close(); 
 +</code>
cpp_tips.1461595982.txt.gz · Poslední úprava: (upraveno mimo DokuWiki)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki