Tipy & triky C++
char* na istringstrem (bez kopírování)
char *mybuf[] = "very very .. long";
istringstream myss(string(mybuf, strlen(mybuf)));
char *mybuf[] = "very very .. long";
istringstream dfile;
dfile.rdbuf()->pubsetbuf(mybuf, strlen(mybuf));
char* do vector<char>
char arr[] = "abcd";
vector<char> buff;
buf->insert(buf->end(), arr, arr + strlen(abcd);
stringstream na cout/string
- 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;
}
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
is.clear();
is.seekg(0);
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
// declaration
void setSomething(int val1 = 1, int val2 = 2, int val3 = 3);
// definition
void setSomething(int val1, int val2, int val) {
this.val1 = val1;
this.val2 = val2;
this.val3 = val3;
}
// calling
setSomething(1);
setSomething(1,2);
setSomething(1,2,3);
Zákeřné dočasné objekty
první varianta
v každé iteraci se provádí znovu alokace paměti pro dočasný objekt str včetně kopírování obsahu
nejspíš dokonce dvojnásobně, ještě pro volání size
valgrind naměřil (celý program): total heap usage: 9,890 allocs, 9,868 frees, 1,207,634 bytes allocated
int i;
for (i=0; i<outstr.str().size(); ++i) {
hash = ((hash << 5) + hash) + outstr.str()[i]; // hash * 33 + c
}
for (string::const_iterator it = outstr.str().begin(); it != outstr.str().end(); ++it) {
hash = ((hash << 5) + hash) + *it; // hash * 33 + c
}
třetí varianta
správné řešení
teoreticky se ale kopíruje paměť str objektu do mystr
valgrind naměřil (celý program): total heap usage: 9,148 allocs, 9,126 frees, 913,802 bytes allocated
string mystr(outstr.str());
for (string::const_iterator it = mystr.begin(); it != mystr.end(); ++it) {
hash = ((hash << 5) + hash) + *it; // hash * 33 + c
}
čtvrtá varianta
mělo by být nejvíce šetrné k paměti
objekt str by se neměl kopírovat, měla by se pouze prodloužit jeho životnost
hrozí zde stále nebezpečí přepsání obsahu.. ukazatel ukazuje na interní buffer, který se může při práci se stringstream měnit
valgrind naměřil překvapivě stejný počet alokací, jako v předchozím případě. Nejspíš zabrala nějaká optimalizace při kompilaci
const string& mystr = outstr.str();
for (string::const_iterator it = mystr.begin(); it != mystr.end(); ++it) {
hash = ((hash << 5) + hash) + *it; // hash * 33 + c
}
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í)
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++?
stringstream out(stringstream::out|stringstream::binary)
out.write((char *) &acc, sizeof(struct MyRecord));
..
out.write( rec.location.c_str(), rec.location.size() ); // string
out.write( (char*) & rec.account_num, sizeof( rec.account_num ) ); // int
..
Mapování struct do vector<char>
vector<char> v(sizeof(mystruct));
mystruct *s = reinterpret_cast<mystruct*>(v.data());
Velikost struktury s polem znaků
struct mystruct {
char data[];
}
struct mystruct {
char data[1];
}
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
#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();
}
Memory leak bez virtuálního destruktoru
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;
}
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:
virtual ~Interface() {}
Soubor do paměti
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();
}
Paměť do souboru
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();