#8 Petr
Tebe by stacilo toto:
struct VERTEX{
float x;
float y;
float z;
};
#include <vector>
int main(){
std::vector<VERTEX> data(7);
data[0].x = 7;
data[0].y = 8;
data[1].x = 9;
data[1].z = 10;
//....
}
Ty si si v podstate implementoval binarny strom kde je hodnota uzlu totozna s klucom (mohol si pouzit kontainer std::set). Tebe by sa viac oplatilo pouzit std::map, cize kazdy uzol ma 'kluc' podla ktoreho sa zoraduje a 'hodnotu' ktora obsahuje cisla riadkov. Napr:
struct Node{
std::string key; //slovo
std::vector<size_t> value; //cislo riadkov na ktorych sa dane slovo nachadza
Node* l, r;
};
//-----------------------------------------------
//pomocou stl:
std::map<std::string, std::vector<size_t>> words;
words["slovo"].push_back(3);
words["slovo"].push_back(6);
words["slovo2"].push_back(7);
//...
Na STL je dobra tato kniha: http://www.amazon.com/gp/product/0321623215/ (ak nechces podporit autorov tak je aj na TPB)
Zanedlho ma vyst tato kniha ktora vyzera velmi dobre: http://www.amazon.com/The-Programming-Language-4th-Edition/dp/0321563840/
#2 Lukáš
Na prevod cisel v oct, dec a hex formate mozes pouzit std::stringstream(a manipulatory std::oct, std::dec, std::hex) alebo std::sscanf (%d, %o, %x). Nacitanie a vypis ciesel v binarnom formate si musis naprogramovat sam ale na tomto fore je uz dost vela rieseni, staci hladat.
Vypis cisla v binanom formate sa lahko robi pomocou bitovych masiek(algoritmus je medz komentami //A a //B):
#include <iostream> template <typename Integer> struct Bin{ const Integer num; operator Integer()const{return num;} }; template <typename Integer> Bin<Integer> bin(Integer num){return Bin<Integer>{num};} template <typename Integer> std::ostream& operator<<(std::ostream& out, Bin<Integer> bin_num){ typedef typename std::make_unsigned<Integer>::type UnsignedInteger; //A UnsignedInteger num = bin_num; for(UnsignedInteger mask = 1; mask /*&& (mask <= num)*/; mask *= 2){
if(num & mask)out << '1'; else out << '0'; } //B return out; } int main(){ using namespace std; std::cout << bin<char>(95) << endl << bin<short>(34395) << endl << bin(9034395) << endl << bin(47392999034395L) << endl; }
#3 kedlik
Pouzi cyklus (for, while, do-while).
cyklus{
printf("Zadej pocet kotoucu :\n") ;
scanf("%i", &n);
if (n>10){
//...
}
else if (n<0){
//...
}
else{
stop_cyklu;
}
}
cnt=PVez(n,1,2,3);
printf("Pocet volani: %i\n", cnt);
getchar();
return 0;
#13 Sefiros
Akonahle funkcia vracia premennu, tak vratena premenna je rvalue. Ak chces vytvorit referenciu na rvalue tak ta referencia musi byt konstantna:
Tu mas moznosti kopirovacich konstruktorov (tvoja trieda moze mat aj vsetky 3):
//1.
Matrix(Matrix& m){/*...*/} //ako parameter moze byt lvalue, co je hociaka premenna s menom alebo ina referencia
//2.
Matrix(const Matrix& m){/*...*/} //ako parameter sa moze pouzit lvalue aj rvalue (rvalue su docasne premenne ako vysledok dakeho vyrazu, vratena premenna z funkcie, ...)
//3.
Matrix(Matrix&& m){/*...*/} //ako parameter sa moze pouzit len rvalue
//vysledok tohto vyrazu je rvalue a ten moze byt skopyrovany len konstruktorom 2. a 3.
third+first;
edit:
Tvoj kod sa da o dost sprehladnit:
template <class T>
std::ostream& operator<<(std::ostream& out, Matrix<T>& m){
for (int i=0;i<m.returnHeight();++i){
for (int y=0;y<m.returnWidth();++y){
out << m.at(y,i) << ", ";
}
out << std::endl;
}
return out;
}
template <class T>
Matrix<T> make_random_matrix(int r, int s){
Matrix<T> m(r, s);
for (int i=0;i<m.returnHeight();++i)
{
for (int y=0;y<m.returnWidth();++y)
{
m.fill(y,i,rand()%100);
}
}
return m;
}
int main()
{
using namespace std;
Matrix<int> first = make_random_matrix<int>(3, 3);
cout << "FIRST: " << endl << first << endl;
Matrix<int> second = make_random_matrix<int>(3, 3);;
cout << "SECOND: " << endl << second << endl;
Matrix<int> third = second;
cout << "THIRD: " << endl << third << endl;
third = third+first;
cout << "THIRD+FIRST: " << endl << third << endl;
return 0;
}
edit2:
Doporucujem ti vsade kde mozes davat const, napr:
template <class T>
class Matrix
{
/*
...
*/
//matica 'givenMatrix' sa nebude menit, tak ju oznac ako const
Matrix(const Matrix<T> &givenMatrix);
//matica 'givenMatrix' sa nebude menit, tak ju oznac ako const
Matrix<T>& operator=(const Matrix<T> givenMatrix);
//matica 'givenMatrix' sa nebude menit, tak ju oznac ako const
//matica 'this' sa tiez nebude menit, tak oznac metodu ako const
Matrix<T> operator+(const Matrix<T> &givenMatrix)const;
//getery tiez oznac ako const:
int returnWidth()const{return width;}
int returnHeight()const{return height;}
operator bool()const{return fail;}
//verzia at() ktora umoznuje upravovat prvky v matici:
T& at(int m_width,int m_height);
//verzia at ktora neumoznuje upravovat prvky v matici
const T& at(int m_width,int m_height)const;
};
#8 Sefiros
Konstruktor sa vola pri vytvoreni triedy a destruktor sa vola ked objekt zanika.
V podstate pred volanim konstruktora obsahuje trieda nahodne data. Ty si zavolal destruktor na zaciatku construktora. Cize premenna 'dataCore' obsahovala nahodnu adresu a ty si s nou pracoval ako s dynamicky alkovanym polom.
Ty si pouzil na vytvorenie matice 2 rozmerne pole, s nim sa lepsie pracuje, ale dlhsie trva jeho vytvorenie a mazanie.
ingiraxo pouzil 1 rozmerne pole, to sa alokuje jednoduhsie (staci 1 new/delete), ale zas sa s nim horsie pracuje lebo musis vyratavat index podla velkosti matice a taky operator[] sa bude musiet riesit cez medzi triedu...
Obydva sposoby sa daju pouzit, kazdy ma vlastne vyhody/nevyhody. Ak si opravys chyby v tvojom kode tak to nemusis cele prerabat.
#1 Sefiros
#include <stdexcept>
template <class T>
matrix<T> /*<-musis specifikovat aj template parameter navratoveho typu ak je definicia mimo triedy*/
matrix<T>::operator+(const /*<- parameter funkcie sa nebude menit*/ matrix<T> &x)const /*<- this funkcie sa nebude menit*/{
//ak chces pouzivat konstruktory a operatory v ktorych moze nastat chyba, ale nemozes ju vratit ako navratovu hodnotu tak sa oplati pouzivat vynimky:
if(width != x.width || height != x.height)throw std::logic_error("pokus o scitnie 2 matic s roznymi velkostami");
//this sa kludne moze rovnat parametru x:
matrix temp(width,height);
for(int i=0; i < width; ++i)
for(int y=0;y < height;++y)
temp.dataCore[i][y] = dataCore[i][y] + x.dataCore[i][y];
//treba mat copy construtor, idealne aj move constructor (c++11)
return temp;
}
Ak pouzivas c++11, sprav aj move constructor kvoly tomu aby pri vracani matice nevznikali zbitocne kopie.
Ak nepozivas c++11, pretaz radsej matrix& operator+=(const matrix& ).
operator= mas ties zle.
Kedze sa chces dostat z kazdeho uzla na vsetky ostatne tak predpokladam ze je to cykliky graf. V podstate ti staci vybrat si hociaky uzol a zacat vytvarat nahodne cestu (pridavat orientaciu hranam) dovtedy dokym sa nedostanes do uzlu z ktoreho si prisiel. Potom si vyberes hociaky iny uzol z ktoreho vychadza neoriantovana hrana a spravys to iste ak predtym dokym sa nedostanes do uzlu ktory neobsahuje neorientovane hrany. Opakujes to dokym graf obsahuje neorientovane hrany.
Snad je to dobre :)
Ak nasobis integer s charom tak vysledok je integer:
Znak 'i' ma hodnotu 105, ak ho vynasobis 3 tak mas 315.
Ak si chcel znak vypisat 3x tak si mal spravyt nieco taketo:
std::cout << z[0] << z[0] << z[0];
Preco si vlastne pouzil jednoprvkove pole?
#5 Martin
Treba na to stiahnut kniznicu.
Pod nepovinnymi medzerami som mal na mysli nieco taketo:
//medzery na spravnych miestach sa ignoruju:
1,3,1000,-2,4,1000
1,3 , 1000,-2, 4,1000
1 , 3, 1000,-2,4,1000
1, 3,1000, -2, 4,1000
Ak predpokladas ze vstupny retazec je spravne zadany a nemusis ho kontrolovat tak ti bude stacit aj stringstream ako napisal crazy.
Pre trochu zlozitejsie veci daky tokenizer (strtok, boost::tokenizer, alebo si napis vlastny)
Mozno by sli pouzit aj regexy, tie su ale az v c++11(v gcc nefunguju) alebo v booste.
Mozes si spravyt aj stavovy automat, to je asi najpracnejsie, ale mas najviac moznosti.
#1 Martin
Riesit sa to da vela sposobmi, zalezi od ci tam chces mat volitelne udaje ako nepovinne medzery a pod.
Najjednoduhsie je asi pouzitie boost::tokenizer
#3 Karel Bern
Ak chces zobrazit menu pred kazdou volbou tak ho zobrazuj vo vnutri cyklu.
#4 bak
Suhlasim s tym ze pouzivanie goto by sa malo obmedzit na minimum, ale toto je jeden z mala prikladov kde je dobre pouzit goto. Akonahle mas vnorene cykly alebo switche tak s break-om vyskocis len z jedneho cyklu/switchu. Pomocou goto mozes vyskocit z viacerych, je to rychlejsie a prehladnejsie ako testovat flagy.
#9 hoacin
Sice ti neodpoviem na tvoju otazku (neovladam OpenMP) ale tvoj kod sa da urychlit aj inymi sposobmi.
Najprv by si sa mal vykaslat na qsort. Radsej pouzi std::sort ktory umoznuje inlinovat porovnavaciu funkciu.
Aky pouzivas kompilator? (Nemozes pouzit thready z c++11 ? http://en.cppreference.com/w/cpp/thread)
Mozes pouzit quick sort a merge sort. Na tych linkoch mas obrazky ako funguju, pole vecsinou delis na viacej casti a tie potom rekruzivne sortujes. Mozes sortovat kazdu cast v inom vlakne. Pouzivas c alebo c++?
Na to sa pouziva kruhovy buffer, pekne je to vysetlene tu: http://en.wikipedia.org/wiki/Circular_buffer
Mozes skusit nieco taketo:
#include <iostream>
#include <vector>
#include <mutex>
#include <future>
#include <chrono>
#include <thread>
//pointer na data ktory uzamkne mutex
template <class T, class M = std::mutex>
class lock_ptr{
T* ptr;
M &m;
public:
T* operator->(){return ptr;}
T& operator*(){return *ptr;}
lock_ptr(T* t, M& m):ptr(t), m(m){
m.lock();
}
~lock_ptr(){
m.unlock();
}
};
template <class T, class M = std::mutex>
lock_ptr<T, M> make_lock_ptr(T* t, M& m){return lock_ptr<T, M>(t, m);}
class C{
std::vector<int> a;
std::mutex m_a;
std::vector<int> b;
std::mutex m_b;
public:
lock_ptr<std::vector<int>> lock_a(){return make_lock_ptr(&a, m_a);}
lock_ptr<std::vector<int>> lock_b(){return make_lock_ptr(&b, m_b);}
};
int main(){
C c;
auto a1 = std::async(std::launch::async, [&c](){
auto x = c.lock_a();
std::this_thread::sleep_for( std::chrono::seconds(2) );
for(int i = 0; i < 10000; ++i)
x->push_back(i);
std::cerr << "a1 end\n";
});
auto a2 = std::async(std::launch::async, [&c](){
auto x = c.lock_b();
for(int i = 10; i > 0; --i)
x->push_back(i);
std::cerr << "a2 end\n";
});
auto a3 = std::async(std::launch::async, [&c](){
auto x = c.lock_a();
std::cerr << "a3 end\n";
});
}
#5 ingiraxo
Lamda funkcie bez atributov mozes jednoducho pretypovat na pointer, cize vies adresu. V pripade lamdy s atributom je to trochu zlozitejsie:
//lambdy bez atributov:
void (*fnc1)(const std::string&) = [](const std::string& s)->void{};
void (*fnc2)(const std::string&) = [](const std::string& s)->void{};
if(fnc1 == fnc2);
else;
//s atributmi:
int i;
auto a1 = [&i](){return i+1;};
auto a2 = [&i](){return i+2;};
//
if(reinterpret_cast<void*>(&decltype(a1)::operator()) == reinterpret_cast<void*>(&decltype(a2)::operator()));
else;
//pripdane mozes porovnavat adresy samotnych objektov, vtedy ale nesmies lambda objekt kopirovat
#1 ingiraxo
Lamda funkcia je v podstate trieda s pretazenym operatorom (). Ak neprebera lamda ziadne atributy tak sa moze pretypovat na pointer na funkciu (vtedy je perator() staticka metoda).
Z lamdou mozes pracovat ako s akymkolvek inym objektom.
(lamda ma standartne aj kopy konstruktor a operator= ak tomu nebrania atributy lambdy)
#13 Luckin
http://www.youtube.com/watch?v=OB-bdWKwXsU 37:10
#11 Luckin
rvalue referencia. Pouziva sa na presuvanie objektov:
#include <iostream>
class C{
double* data;
public:
C(){
std::cout << "C()\n";
data = new double[10000];
}
~C(){
std::cout << "!C()\n";
delete[] data;
}
C(const C& c){ //copy constructor (musi prekopyrovat vsetkych 10k prvkov)
std::cout << "C(const C&)\n";
data = new double[10000];
for(size_t i = 0; i < 10000; ++i)
data[i] = c.data[i];
}
C(C&& c){ //move constructor (iba presunie prvky, konstruktor vie ze objekt c sa uz nebude pouzivat)
std::cout << "C(C&&)\n";
data = c.data;
c.data = nullptr;
}
};
C create_C(){
C c;
return c; //vola sa move constructor
return C(); //toto zabrani optimalizaciam...
}
int main(){
C c1;
C c2(c1); //vola sa copy constructor
C c3 = create_C();
}
http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
#6 Luckin
Da sa to riesit aj ovla efektivnejsie:
#include <iostream>
#include <type_traits>
#include <stdexcept>
template <class T, size_t N>
class stack{
private:
char data[sizeof(T)*N];
size_t pos;
inline T* t_data(size_t i){return reinterpret_cast<T*>(data) + i;}
inline const T* t_data(size_t i)const{return reinterpret_cast<const T*>(data) + i;}
public:
inline size_t size()const{return pos;}
inline constexpr size_t max_size()const{return N;}
inline bool empty()const{return (pos == 0);}
inline bool full()const{return (pos == N);}
stack():pos(0){}
~stack(){
if(!std::is_trivial<T>::value) //ak nemas c++11 tak tuto podmienku odstran
for(size_t i = pos; i > 0; --i)
t_data(i-1)->~T();
}
void clear(){
this->~stack();
pos = 0;
}
template <class U>
void push(const U& u){
if(full())throw std::out_of_range("stack is full");
new(t_data(pos)) T(u);
++pos;
}
void push(T&& t){ //ak nmas c++11 tak tuto metodu odstran
if(full())throw std::out_of_range("stack is full");
new(t_data(pos)) T(std::move(t));
++pos;
}
template <class... Args>
void emplace(Args... args){ //ak nmas c++11 tak tuto metodu odstran
if(full())throw std::out_of_range("stack is full");
new(t_data(pos)) T(args...);
++pos;
}
void pop(){
if(empty())throw std::out_of_range("stack is empty");
--pos;
t_data(pos)->~T();
}
const T& top()const{
if(empty())throw std::out_of_range("stack is empty");
return *t_data(pos-1);
}
T& top(){
if(empty())throw std::out_of_range("stack is empty");
return *t_data(pos-1);
}
};
#4 Luckin
Hlavna nevyhoda tvojho stacku je to, ze aj ked v nom nic nie je tak sa vola 'n' krat konstruktor/destructor. Dalsia nevyhoda je ze ak chces do toho stacku vlozit objkt tak musi mat pretazeny operator=. Dalsia nevyhoda je ze v Pop a Push sa vytvaraju zbitocne kopie objektov...
Zasobnik(stack) moze byt implementovany roznymi sposobmi. Stack nie je ani tak datova struktura ako skor sposob ako sa do takej struktury ukladaju data. Implementovany moze byt pomocou ronych linearnych datovych struktur ako pole, dynamicke pole(vector), rada, zretazeny zoznam(list)...
Viac mas toho tu: http://cs.wikipedia.org/wiki/Z%C3%A1sobn%C3%ADk_(datov%C3%A1_struktura)
Riesenie od Luckin-a je viac menej funkcne ale je nevhodne na ukladanie zlozitejsich typov .
operator mozes vytvorit ako frienda alebo ako metodu:
struct Matrix{
Matrix operator+(const Matrix& m)const{
Matrix temp;
//temp = (*this + m)
return temp;
}
//alebo:
friend Matrix operator+(const Matrix& a, const Matrix& b){
Matrix temp;
//temp = (a + b)
return temp;
}
};
Doporucujem ti spravyt aj move constructor (ak mas c++11) alebo mieso operatora+ pretazit operator+=
#4 Michal
stdexcept je tam len kvoly vynimke std::logic_error.
Ak sa ti nechce implementovat vlastny stack, tak mozs pouzit adapter std::stack.
#include <stack>
#include <iostream>
int main(){
std::stack<int> stack; //alebo std::stack<int, std::vector<int>> stack;
stack.push(1);
stack.push(2);
stack.pop();
stack.push(3);
std::cout << stack.top();
}
Ja som si uz raz implementoval stack ktory pouziva polia, kludne ho mozes pouzit ak chces:
#include <iostream>
#include <algorithm>
#include <initializer_list>
#include <type_traits>
template <class T, size_t N>
class stack final{
template <typename, size_t>
friend class stack;
public:
typedef T value_type;
typedef T& reference;
typedef const value_type& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
private:
char data[sizeof(value_type)*N];
size_t pos;
inline pointer t_data(size_t i){return reinterpret_cast<pointer>(data) + i;}
inline const_pointer t_data(size_t i)const{return reinterpret_cast<const_pointer>(data) + i;}
public:
stack():pos(0){}
stack(size_t n){
pos = std::min(N, n);
for(size_t i = 0; i < pos; ++i)
new(t_data(i)) value_type();
}
stack(size_t n, const_reference t){
pos = std::min(N, n);
for(size_t i = 0; i < pos; ++i)
new(t_data(i)) value_type(t);
}
template <class U, size_t M>
stack(const stack<U, M>& s){
pos = std::min(N, s.pos);
for(size_t i = 0; i < pos; ++i)
new(t_data(i)) value_type(*s.t_data(i));
}
template <class U, size_t M>
stack(stack<U, M>&& s){
pos = std::min(N, s.pos);
for(size_t i = 0; i < pos; ++i)
new(t_data(i)) value_type(std::move(*s.t_data(i)));
}
template <class I>
stack(I beg, I end){
for(pos = 0; (beg != end) && (pos < N); ++beg, ++pos)
new(t_data(pos)) value_type(*beg);
}
stack(std::initializer_list<T>&& inic_list){
auto beg = std::begin(inic_list);
auto end = std::end(inic_list);
for(pos = 0; (beg != end) && (pos < N); ++beg, ++pos)
new(t_data(pos)) value_type(std::move(*beg));
}
~stack(){
if(!std::is_trivial<value_type>::value)
for(size_t i = pos; i > 0; --i)
t_data(i-1)->~value_type();
}
void clear(){
if(!std::is_trivial<value_type>::value)
for(; pos > 0; --pos)
t_data(pos-1)->~value_type();
pos = 0;
}
size_t size()const{return pos;}
constexpr size_t max_size()const{return N;}
bool empty()const{return (pos == 0);}
bool full()const{return (pos == N);}
template <class U>
void push(const U& u){
new(t_data(pos)) value_type(u);
++pos;
}
template <class U>
void push(U&& u){
new(t_data(pos)) value_type(std::move(u));
++pos;
}
template <class... Args>
void emplace(Args... args){
new(t_data(pos)) value_type(args...);
++pos;
}
void pop(){
--pos;
t_data(pos)->~value_type();
}
const_reference top(){
return *t_data(pos-1);
}
};
Ten tvoj zasobnik by mohol vyzerat takto:
#include <stdexcept>
template <class T, size_t N>
class Stack
{
private:
T data[N];
size_t pointer;
public:
Stack():pointer(0){}
bool IsEmpty(){return (pointer == 0);}
bool IsFull(){return (pointer == N);};
void Push(const T& t){
if(IsFull())throw std::logic_error("Zasobnik je plny!");
data[pointer++] = t;
}
T Pop(){
if(IsEmpty())throw std::logic_error("Zasobnik je prazdny!");
return data[--pointer];
}
};
int main(void)
{
Televize t1;
Televize t2;
Televize t3;
Stack<Televize, 3> s1;
s1.Push(t1);
s1.Push(t2);
s1.Pop();
s1.Push(t2);
return 0;
}
mozes pouzit fflush(stdin) na vycistenie streamu. Vecsinou to funguje, ale nie je to zarucene.
Pripadne si mozes spravyt vlastnu funkciu:
void fclear(FILE* f){ int i; while( (i = fgetc(f)), (!feof(f) && !ferror(f) && i != '\n')); //netestoval som to
} //.... fclear(stdin);
#3 Martin Kozibrátka
V tom linku od crazy-ho to mas pekne vysvetlene, ale skratene:
C pretpovanie kombinuje prve 3 pretypovania.
Mozes si spravyt upravene binarne vyhladavanie ktore bude hladat adresu/index najvecsieho prvka pola ktory je mensi ako prvok ktory chces do pola vlozit. Potom vsetky prvky ktore su napravo od najdeneho prvka posunies (napr pomocou memcpy, ak treba tak zvecsis pole). Potom vlozis na uvolnenu poziciu novy prvok.
Dalej ma napada ze mozes prvky vkladat na koniec pola, a pred vyhladavanim spustis daky sort(napr quick sort, marge sort) ktory usporiada pole (v dakej premennej si uchovavaj stav pola: zotridene/nezotriedene).
Dalej mozes miesto pola pouzit binarny strom (nieco na sposob std::set, std::map).
//.....
Vo vsetkych pripadoch mozes urychlit porovnavanie prvkov tym ze budes porovnavat hashe prvkov (na sposob std::unordered_map)
std::string je vlastne pointer ktory ukazuje na dynamicky alokovane pole charov (pripadne aj dalsie data). To znamena ze velkost stringuje je na 64bit systeme vecsinou 8B. Struktura S ma len 2 stringy, takze samotna struktura zabera len 16B co je strasne malo. Takze kludne mozes pouzit pole v ktorom budu priamo ulozene data, nemusis dynamicky alokovat kazdy prvok (co je o dost pomalsie ako alokovanie jedneho bloku naraz). V pripade stringu mozes na kopirovanie pouzit std::memcpy co sposobi ze sa nebude volat zbytocne kopirovaci/presuvaci konstruktor (std::vektor funguje podobne).
Uchovavanie v poli pointre na prvky miesto samotnych prvkov ma dalsiu nevyhodu. Kedze su jednotlive prvky alkovane dynamicky tak su rostrusene po heape. To sposoby ze program nemoze natiahnut cely blok dat do cache pamete a kvoly kazdemu jednemu prvku ho musi nacitavat z ram, cize dalsie spomalenie.
Tvoje riesenie ma jednu vyhodu. Ak realokujes pole, tak adresa prvku ostane rovnaka, takze mozes vytvarat pointre na prvky a po realokovani pola su pointre stale OK co pri std::vectore neplati (vecsinov tato vlastnost nie je potrebna)
Takze aj ked si myslis ze pole pointrov na data bude efektivnejsie ako pole dat, tak to bude skor opacne (Samozrejme implementacia dynamcikeho pola tak aby sa zbytocne nevolali konstruktory nie je uplne trivialna)
----------------------------------
Tvoje riesenie je ok, a tam kde si napisal ze mas memory lake ho naozaj mas, riesenie je jednoduche:
size_t pocetPrvkov = N; //pocet prvkov v poly
size_t povodnaVelkost = N; //velkost pola
size_t zvetsenaVelikost = N + X; //velkost zvecseneho pola, je dobre ak X > 1 neh sa nemusi casto realokovat
S** polePointeru;
S ** tmp = new S*[zvetsenaVelikost]; // nove vetsie pole
std::memcpy(tmp, polePointeru, sizeof(S*)*povodnaVelkost); //skopyruje pointre, netreba znovu alokovat kazdy prvok
delete [] polePointeru; //zmaze povodne pole
polePointeru = tmp;
//--------------------------------------------------------------
//pridanie prvku do pola:
polePointeru[pocetPrvkov] = new S;
++pocetPrvkov;
Skus si to skompilovat pomocou c++ kompilatoru, vypise ti mnozstvo chyb a warningov ktore ti pomozu:
error: cannot initialize a parameter of type 'double (*)()' with an lvalue of type 'rfunc' (aka 'double (*)(double)')
ic = (*f[i])(ivals[2*j], ivals[2*j], approx[j], rf[j]);
^~~~~
untitled.cpp:52:18: error: too many arguments to function call, expected 0, have 1
sum += func(x+h);
~~~~ ^~~
untitled.cpp:61:18: error: too many arguments to function call, expected 0, have 1
sum += func((x+h)/2.0);
~~~~ ^~~~~~~~~
#3 Dejv
Tak si vektor implmentuj sam, ak ste este nepreberali dynamicku alokaciu pamete tak mozes pouzit len polia:
const unsigned MAX = 100;
Firma vsetky_firmy[MAX];
unsigned pocet_firiem = 0;
Vlastnik vsetci_vlastnici[MAX];
unsigned pocet_vlastnikov = 0;
struct Firmy;
struct Vlastnici
{
string name1;
string adr1;
Firmy* list_F[MAX];
unsignd pocet_firiem = 0;
};
struct Firmy
{
string name2;
string adr2;
Vlastnici* list_V[MAX];
unsignd pocet_vlastnikov = 0;
};
#1 David
Jedna z moznosti je mat centralny zoznam vsetkych firiem a vlastnikov. Napr:
std::list<Firma> vsetky_firmy;
std::list<Vlastnik> vsetci_vlastnici;
Kazda firma bude potom obsahovat pointre na Vlastnikv a Vlastnici zas pointre na Firmy. V podstate to mas dobre, len misto pola by som pouzil vektor nech nemusis rucne alokovat/dealokovat pamet:
struct Firmy;
struct Vlastnici
{
string name1;
string adr1;
std::vector<Firmy*> list_F;
};
struct Firmy
{
string name2;
string adr2;
std::vector<Vlastnici*> list_V;
};
Akym sposobom najlepsie reprezentovat uzly v AST?
Momentalne pouzivam nieco taketo:
class Root;
class Node{
public:
enum TypeId{/*...*/}; //Dvolezite na implementaciu rychleho dynamic_castu (na sposob llvm::isa a llvm::dyn_cast)
private:
const TypeId TyId;
private:
Node* parent;
Node* prev_sibling;
Node* next_sibling;
Node* first_child;
Node* last_child;
public:
Root& root; //koren stromu obsahuje rozne globalne data (globalne z hladiska mojho jazyka, nie c++)
/*
...
*/
};
class Root : public Node{/*...*/};
//...
Takychto nodov mam v strome stovky/tisice a kazdy uzol zabera minimalne 64B co sa my zda strasne vela. Je daka uspornejsia forma ako reprezentovat uzly stromu?
Pouzivas memcpy() na triedu s netrivialnym konstruktorom/destructorom. std::string v destruktore uvolnuje pamet, akonahle vytvoris jeho bitovu kopiu pomocou memcpy(), tak budes mat 2 stringy ktore ukazuju do tej istej pamete, takze sa ti uvolni 2x a to je chyba.
Riesis to strasne zlozito, jednoduhsie by to vyzeralo nasledovne:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <map>
#include <iterator>
#include <algorithm>
using namespace std;
struct data_t{
long a = 0;
long b = 0;
};
typedef std::map<std::string, data_t> db_t;
struct line_t{
std::string name;
long num;
friend std::istream& operator>>(std::istream& in, line_t& line){
std::string tmp;
std::getline(in, tmp);
//tu by sa hodilo kontrolovat spravnost retazca:
std::stringstream ss(tmp);
ss >> line.name >> line.num;
return in;
}
};
int main (){
db_t db;
std::ifstream a("a.txt");
for(std::istream_iterator<line_t> i(a); i != std::istream_iterator<line_t>(); ++i){
db[i->name].a = i->num;
}
std::ifstream b("b.txt");
for(std::istream_iterator<line_t> i(b); i != std::istream_iterator<line_t>(); ++i){
db[i->name].b = i->num;
}
for(db_t::iterator i = db.begin(); i != db.end(); ++i){
std::cout << i->first << " " << i->second.a << " " << i->second.b << "\n";
}
return EXIT_SUCCESS;
}
#7 Ilhvm
//subor.hpp
class C{
/*
Tu musia byt vsetky atributy(premenne) a deklaracie metod
*/
int i;
float f;
double d;
//...
public:
C();
int metoda(int, float);
void metoda2();
//...
};
//-----------------------------------------------------------------
//subor.cpp
#include "subor.hpp"
/*
tu nedefinujes ziadne atributy, len metody (pripadne staticke premenne)
*/
C::C(){
//...
}
int C::metoda(int x, float y){
//...
}
void C::metoda2(){
//...
}
#1 Tingf11
Mozes pouzit boost filesystem. Ak pouzivas VS2012 tak tam mozes pouzit: ms filesystem. Tieto kniznice su velmi podobne a zrejme budu standardizovane v nasledujucej verzi c++.
Skus daco taketo, len to musis upravyt tak aby to vypisovalo cisla a nie hviezdicky (zaporne a viac ciferne) a zrejme nebude dobre zacinat priamo od stredu (tam su moc natlacene na sebe), ale to sa da upravyt zmenou konstant vo funkcii fnc().
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define MAX_X 30
#define MAX_Y 60
struct point{
size_t x;
size_t y;
};
// "rovnica spiraly", cim vecsie cislo, tym dalej od stredu:
point fnc(int n){
double abs_n = abs(n);
point p;
//polomer:
double rx = ((double)MAX_X) * abs_n/80.;
double ry = ((double)MAX_Y) * abs_n/80.;
//suradnice:
p.x = lround(((double)MAX_X)/2. + rx*cos((0.3 * abs_n)));
p.y = lround(((double)MAX_Y)/2. + ry*sin((0.3 * abs_n)));
return p;
}
int main(){
char matrix[MAX_X][MAX_Y];
//vynulovanie matice:
for(size_t a = 0; a < MAX_X; ++a)
for(size_t b = 0; b < MAX_Y; ++b)
matrix[a][b] = ' ';
//vytvorenie spirali do matice:
for(int i = 0; i < 50; ++i){
point p = fnc(i); //nacita suradnice bodu pre cislo i
if(p.x < MAX_X && p.y < MAX_Y) //nesmie byt mimo matice
matrix[p.x][p.y] = '*';
}
//vypis matice:
for(size_t a = 0; a < MAX_X; ++a){
for(size_t b = 0; b < MAX_Y; ++b){
printf("%c", matrix[a][b]);
}
printf("\n");
}
}
#22 marpit
template <class T> struct List1
{
private:
struct item
{
T value;
item *next;
item(const T& v):
value(v), //typ T musi mat kopirovaci konstruktor
next(nullptr){}
};
item *current = nullptr; //atributy sa daju inicializovat aj takto
item *head = nullptr;
public:
List1();
~List1();
void insert(const T&); //referencia
const T& get(); //referencia
void erase(const T); //toto sa riesi inak (vecsinou cez iteratori ktore nemas implementovane)
//...
};
template <class T>
void List1<T>::insert(const T& value){
item *newItem = new item(value); //tu sa vyuzie ten novy konstruktor z item
newItem->next = head;
head = newItem;
}
//---------------------------------------------------
template <class T> struct Stack1{
private:
T *arr;
/*
* velkost bude zrejme nezaporna, cize radsej pouzi 'unsigned' alebo 'size_t' co je vecsinou 'unsigned long'
* nemusis potom kontrolovat ci uzivatel nezadal zaporne cislo
*/
size_t size;
size_t index;
size_t sp;
public:
Stack1(size_t, size_t);
~Stack1();
//provizorně
Stack1(const Stack1 &s):
//lepsi sposob inicializacie (aj ked pri integeroch je to jedno):
sp(s.sp),
size(s.size),
index(s.index){
/*
this->sp = s.sp;
this->size = s.size;
this->index = index;
*/
//this->arr = s.arr; //toto nestaci, ty musis spravyt hlbkovu kopiu
this->arr = new T[size];
/*
*
* treba prekopyrovat vsetky prvky z pola 's.arr' do 'arr'
*/
for(size_t i = 0; i < size; ++i){
/*
* T musi mat operator=, ak by si to chcel bez neho tak musis pouzit placement new alebo malloc
* a volat konstruktory a destruktory rucne
*/
arr[i] = s.arr[i];
}
}
//...
};
#8 marpit
Riesit sa to da takto:
template<class T>
class List{
struct Item{
T data;
Item(const T& data):data(data){}
template <class... P>
Item(P... p):data(p...){} //<-- treba c++11
};
public:
void insert(const T& data){
Item* item = new Item(data);
//...
}
template <class... P>
void insert_new(P... p){ //<-- treba c++11
Item* item = new Item(p...);
}
//...
};
struct X{
X(int, long, double){}
X(const X& x){}
};
int main(){
X x(1, 2, 3.14);
List<X> list;
list.insert(x); //zavola sa kopirovaci konstruktor
list.insert_new(4, 5, 6.28); //zavola sa konstruktor s 3 parametrami (treba c++11)
}
#2
Ten zasobnik tam musis prekopirovat, cize potrebujes kopirovaci konstruktor a funkcia insert bude prebereat referenciu:
template <class T>
void List1<T>::insert(const T& value) // <-- referencia
{
item *newItem = new item;
newItem->value = value; // <- tu sa zavola kopirovaci konstruktor
//edit: nezavola, zavola sa operator=, moja chyba
newItem->next = head;
head = newItem;
}
struct X{
X(const X& x){ //kopirovaci konstruktor
//...
}
};
Ak chces do listu vlozit novy prvok bez volania kopirovacieho konstruktoru tak budes musiet pouzit Variadic templates z c++11:
template <class T>
template <class... Params>
void List1<T>::insert_new(Params... params){
item *newItem = new item(params...); // treba prerobit aj triedu item
//...
}
alebo pouzit std::list :)
Toto zrejme patri do .Net/Javy. Silna referencie je pointer ktory obsahuje reference counter, akonahle je pocet referencii na dany objekt 0 tak ho GC zmaze. Slaba referencia neinkrementuje reference counter, ale ked chces pristupovat k objektu tak ho docasne inkrementuje(vytvori silnu referenciu). Ak slaba referencia ukazuje na objekt ktory uz bol zmazany referencia vrati null. Slabe referencie sa pouzivaju pri cyklickych referenciach. Napr objekt A obsahuje referenciu na objekt B a objekt B obsahuje referenciu na A. Zaroven vsak ziadna referencia (mimo objekty A a B) neukazuje na objekt A a B, cize GC by ich mal zmazat. Ak by boly pouzite 2 silne referencie, tak by referencia v A aj referencia B mala counter nastaveny na hodnotu 1, tym padom by ich GC nezmazal. Ak bude aspon jedna z tych refereni slaba, tak GC moze mazat.
V c++ sa na to pouziva std::shared_ptr a std::weak_ptr.
V Qt sa neviznam, ale localhost sa zadava asi takto:
adresa = QHostAddress(QHostAddress::LocalHost);
Alebo pouzit http://qt-project.org/doc/qt-4.8/qhostinfo.html
#8 petr143
http://curl.haxx.se/libcurl/c/
funkcia fopen vrati pointer na subor a tento pointer sa porovna s NULL. Vysledok tohto porovnania ( 0 alebo 1) sa zapise do f_in. Kedze f_in je pointer a nie integer tak ti to vyhodi warining.
spravne by to malo byt takto:
if( (f_in = fopen("/home/honza/input_file.txt", "r")) == NULL)//...
/*
* Najde maximum v neprazdnom poly
* Velkost pola musy byt znama pri preklade
* Vracia referenciu na maximum
*/
template <typename T, size_t S>
T& max_element(T (&pole)[S]){
static_assert(S>0, "chyba: pole ma 0 velkost");
//....
}
/*
* Najde maximum v neprazdnom poly
* Velkost pola nemusy byt znama pri preklade
* Vracia referenciu na maximum
*/
template <typename T>
T& max_element(T* pole, size_t s){
assert(s>0 && "chyba: pole ma 0 velkost");
//....
}
/*
* Najde maximum z intervalu <begin, end) //end sa nebere ako prvok pola
* Velkost pola nemusi byt znama pri preklade a pole moze byt prazdne.
* Kedze su ako parameter pointre na prvky pola, tak sa da velkost vypocitat ako ((end-begin)/sizeof(T)))
* Vracia pointer na maximum, ak sa nenajde maximum(pole je prazdne) tak vrati end
*/
template <typename T>
T* max_element(T* begin, T* end){
//....
}
/*
* Skoro to iste ako 3. priklad, ale pracuje pre vecsinu kontainerov.
* Kludne to moze byt list(zretzeny zoznam), mapa, stack, ...
*/
template <typename Iterator>
Iterator max_element(Iterator begin, Iterator end){
//....
}
int pole[20];
//...
std::cout << "max: " << *std::max_element(pole, pole+20);
//alebo://...
std::cout << "max: " << *std::max_element(std::begin(pole), std::end(pole));
Na tej stanke mas priklad ako moze vyzerat ta implementacia. Tu mas trochu upavenu verziu:
template<class T>
T* max_element(T* first, T* last)
{
if (first == last) {
return last;
}
T* largest = first;
++first;
for (; first != last; ++first) {
if (*largest < *first) {
largest = first;
}
}
return largest;
}
pole == pointer; //su tam dake rozdieli, ale pre tvoj pripad to vyzera takto:
int pole[8];
int* pointer;
pointer = pole; //pointer ukazuje na 1. prvok pola 'pole'
return pointer; //vratis pointer
Problem je ale inde, ty vracias pointer(pole je tiez pointer) na lokalnu premennu. Po opusteni funckie sa zmaze pole a vrat sa pointer na prvy prvok pola (samozrejme ten prvok tam uz oficialne nie je )
spravnejsie by si si mal spravyt vlastny iterator, hlavne do buducna ak zmenis mapu za nieco ine tak sa to neotkne zvysku kodu:
#include <QCoreApplication>
#include <QSharedPointer>
#include <QMap>
#include <QDebug>
class IUser
{
public:
virtual void show() = 0;
};
class User : public IUser
{
public:
User() {}
void show() {}
void destroy() {}
};
class MainClass
{
public:
MainClass()
{
m_users["a"] = QSharedPointer<User>(new User);
m_users["b"] = QSharedPointer<User>(new User);
}
class iterator : public std::iterator<std::input_iterator_tag, User>{
typedef QMap<QString, QSharedPointer<User> >::const_iterator map_iter_type;
map_iter_type it;
public:
iterator(map_iter_type it):it(it){}
iterator(const iterator&)=default;
User* operator->(){return it->data();}
User& operator*(){return *it->data();}
bool operator==(const iterator& i)const{return it == i.it;}
bool operator!=(const iterator& i)const{return it != i.it;}
void operator++(){++it;}
void operator++(int){it++;}
void operator--(){--it;}
void operator--(int){it--;}
};
inline iterator begin(){return iterator(m_users.begin());}
inline iterator end(){return iterator(m_users.end());}
private:
QMap<QString, QSharedPointer<User> > m_users;
};
int main()
{
MainClass mc;
//v c++11: for(auto& u : mc)u.show();
for(MainClass::iterator i = mc.begin(); i != mc.end(); ++i){
i->show();
}
return EXIT_SUCCESS;
}
#8 ingiraxo
Je to preto ze iterator vo vektore je obycajny typedef na pointer
http://qt-project.org/doc/qt-4.8/qvector.html#iterator-typedefx