Discussion:
Kolejnosc definiowania typow - da sie to obejsc
(Wiadomość utworzona zbyt dawno temu. Odpowiedź niemożliwa.)
Sulsa
2007-06-04 14:44:07 UTC
Permalink
Prosty kod:

class B;

class A{
B b;
};

class B{
A a;
};

prompt > g++ a.cpp
a.cpp:4: error: field 'b' has incomplete type

no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
Marcin 'Qrczak' Kowalczyk
2007-06-04 14:38:31 UTC
Permalink
Post by Sulsa
no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
Chcesz mieć czerwone pudełko, które zawiera w środku zielone pudełko,
które zawiera w sobie czerwone pudełko, które zawiera w sobie zielone
pudełko i tak dalej w nieskończoność? Nie da się.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Sulsa
2007-06-04 16:13:41 UTC
Permalink
On Mon, 04 Jun 2007 16:38:31 +0200
Post by Marcin 'Qrczak' Kowalczyk
Post by Sulsa
no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
Chcesz mieć czerwone pudełko, które zawiera w środku zielone pudełko,
które zawiera w sobie czerwone pudełko, które zawiera w sobie zielone
pudełko i tak dalej w nieskończoność? Nie da się.
Rzeczywiście wybralem strzasznie nie fortunny przykład, w programie
trafił się taki komunikat g++ jak w przedstawionym przezemnie
przykladzie. Problem tkwil w tym ze mialem kazde klase w innym pliku -
pliki te nawzajem sie includowaly(to byla dosyc skaplikowana zaleznosc)
i w zaden sposob nie moglem sie pozbyc tego denerwujacego komunikatu,
mowiacego ze ktorys z typow jest nie dokonca zdefiniowany. W koncu
skonczylo sie tym ze przenioslem kilka z tych klas do jednego pliku i
komunikat sie nie pojawial, niestety ta bardziej rozdrobniona struktura
byla podzielona w bardziej logiczny sposob a jeden duzy plik zaburzyl
to troche. Niestety odtworzenie tego przykladu kosztowalo by mnie juz
zbyt duzo czasu i nerowo, wiec zdecydowalem sie zadac pytanie na
uproszczonym kodzie co jednak bylo moim bledem. Jesli ktos rozumie o co
mi chodzi albo spotkal sie z takim bledem i moze zna jakis ogolny
sposob radzenia sobie z takim problemem to bradzo prosze o odpowiedz.

P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
klas w pliku, jest wiele jezykow w ktorych to nie ma znaczenia i jest
dobrze, wiec czemu w c++ cos takiego dalej jest?
Jakub Debski
2007-06-04 16:14:06 UTC
Permalink
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
klas w pliku, jest wiele jezykow w ktorych to nie ma znaczenia i jest
dobrze, wiec czemu w c++ cos takiego dalej jest?
nie chodzi o kolejność, ale o informacje na temat rozmiaru obiektu. Bez
tego nie mógłbyś przydzielić pamięci dla obiektu.
Języki w których nie jest to wymagane definiują w rzeczywistości
wskaźnik do obiektu, co wiąże się z tym, że odwołania do składowych są
wolniejsze niż w C++.

pozdrawiam
Jakub
Seweryn Habdank-Wojewódzki
2007-06-04 19:39:56 UTC
Permalink
Witam
Post by Jakub Debski
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
klas w pliku, jest wiele jezykow w ktorych to nie ma znaczenia i jest
dobrze, wiec czemu w c++ cos takiego dalej jest?
nie chodzi o kolejność, ale o informacje na temat rozmiaru obiektu. Bez
tego nie mógłbyś przydzielić pamięci dla obiektu.
Języki w których nie jest to wymagane definiują w rzeczywistości
wskaźnik do obiektu, co wiąże się z tym, że odwołania do składowych są
wolniejsze niż w C++.
Czasem jest jeszcze inaczej. Tak chyba było w któryś BC. Można było
definiować kompilację wieloprzebiegową. Kompilator wywala błąd jak obiekt
jest nieokreślony po wykonaniu wszystkich przebiegów. GCC takie nie jest
więc wywal błąd w pierwszym podejściu. Co więcej jak program jest linkowany
i biblioteki są ustawione przed obiektami to też wywala błąd, że nie zna
odwołań.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Jakub Debski
2007-06-04 19:49:29 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Czasem jest jeszcze inaczej. Tak chyba było w któryś BC. Można było
definiować kompilację wieloprzebiegową. Kompilator wywala błąd jak obiekt
jest nieokreślony po wykonaniu wszystkich przebiegów. GCC takie nie jest
więc wywal błąd w pierwszym podejściu. Co więcej jak program jest linkowany
i biblioteki są ustawione przed obiektami to też wywala błąd, że nie zna
odwołań.
Przydatność tego raczej nie wielka... I tak nie poradzi sobie z
określeniem "rekurencyjnego" rozmiaru z przykładu pierwszego posta,
a wątpię, by w prosty sposób dało się przy wieloprzebiegowej kompilacji
wykrywać wszystkie możliwe pętle.

pozdrawiam
Jakub
Seweryn Habdank-Wojewódzki
2007-06-04 21:08:11 UTC
Permalink
Witam
Post by Jakub Debski
Post by Seweryn Habdank-Wojewódzki
Czasem jest jeszcze inaczej. Tak chyba było w któryś BC. Można było
definiować kompilację wieloprzebiegową. Kompilator wywala błąd jak obiekt
jest nieokreślony po wykonaniu wszystkich przebiegów. GCC takie nie jest
więc wywal błąd w pierwszym podejściu. Co więcej jak program jest
linkowany i biblioteki są ustawione przed obiektami to też wywala błąd,
że nie zna odwołań.
Przydatność tego raczej nie wielka... I tak nie poradzi sobie z
określeniem "rekurencyjnego" rozmiaru z przykładu pierwszego posta,
a wątpię, by w prosty sposób dało się przy wieloprzebiegowej kompilacji
wykrywać wszystkie możliwe pętle.
Oczywiście, ale tą rekurencję już omówił Qrczak jako nie za bardzo sensowną.

Na BC pozwalało to pisać kod w bałaganie, pamiętam jak przenośiłem swoje
śmieci z BC na VC 6.0 i nic się nie kompilowało. Ta wieloprzebiegowość była
wygodna - nie wiem czy dobra - dziś tak nie myślę, bo uważam że jak jest
potrzebna wieloprzebiegowość, to znaczy, że kod jest fatalny.
A co do cylki, to jak już zostało powiedziane, albo je nalezy rozwalić
pimplem, albo projekt jest do luftu.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Jakub Debski
2007-06-04 22:58:15 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Oczywiście, ale tą rekurencję już omówił Qrczak jako nie za bardzo sensowną.
rzeczywiście trudno wyobrazić sobie potrzebę wzajemnej relacji "ma".
Post by Seweryn Habdank-Wojewódzki
A co do cylki, to jak już zostało powiedziane, albo je nalezy rozwalić
pimplem, albo projekt jest do luftu.
gdy cykle trzeba rozwalać pimplem to już świadczy, że projekt jest do
luftu :)
pimpl powinien być do redukowania zależności, a nie łatania wad
projektowych.

pozdrawiam
Jakub
Sulsa
2007-06-04 23:29:34 UTC
Permalink
On Tue, 05 Jun 2007 00:58:15 +0200
Post by Jakub Debski
gdy cykle trzeba rozwalać pimplem to już świadczy, że projekt jest do
luftu :)
pimpl powinien być do redukowania zależności, a nie łatania wad
projektowych.
co to jest ten pimpl?
Jedrzej Dudkiewicz
2007-06-05 05:35:37 UTC
Permalink
Post by Sulsa
co to jest ten pimpl?
http://www.gotw.ca/gotw/028.htm
http://www.boost.org/libs/serialization/doc/pimpl.html
http://www.gamedev.net/reference/articles/article1794.asp

1, 2 i 3 hit z google.
Seweryn Habdank-Wojewódzki
2007-06-04 23:20:31 UTC
Permalink
Witam
Post by Jakub Debski
Post by Seweryn Habdank-Wojewódzki
Oczywiście, ale tą rekurencję już omówił Qrczak jako nie za bardzo sensowną.
rzeczywiście trudno wyobrazić sobie potrzebę wzajemnej relacji "ma".
Post by Seweryn Habdank-Wojewódzki
A co do cylki, to jak już zostało powiedziane, albo je nalezy rozwalić
pimplem, albo projekt jest do luftu.
gdy cykle trzeba rozwalać pimplem to już świadczy, że projekt jest do
luftu :)
pimpl powinien być do redukowania zależności, a nie łatania wad
projektowych.
Zdałem w tym wątku osobne pytanie: "A jakie jest merytoryczne uzasadnienie
takiego konceptu?" i nie dostałem odpowiedzi, więc załóżmy, że cykl MUSI
być - nie zależnie od sensowności.

Kiedyś już był o tym flame, że czasem masz cykle w danych - elementy
odwołują się do siebie nawzajem. I wtedy to musisz jakoś ugryźć. Wtedy
podałem rozwiązanie na pograniczu pimpla wykorzystujące shared_ptr i
weak_ptr, aby ten cykl zostawić koncepcyjnie ale osłabić w sensie allokacji
(trochę na podstawie książki Pete Beckera).

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-04 23:29:14 UTC
Permalink
On Mon, 04 Jun 2007 18:14:06 +0200
Post by Jakub Debski
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
klas w pliku, jest wiele jezykow w ktorych to nie ma znaczenia i
jest dobrze, wiec czemu w c++ cos takiego dalej jest?
nie chodzi o kolejność, ale o informacje na temat rozmiaru obiektu.
Bez tego nie mógłbyś przydzielić pamięci dla obiektu.
Języki w których nie jest to wymagane definiują w rzeczywistości
wskaźnik do obiektu, co wiąże się z tym, że odwołania do składowych
są wolniejsze niż w C++.
przeciez taki rozmiar mozna bez problemu okreslic, nie wiem czemu w c++
jest to zrobione tak prymitywnie ze znany jest jedyni rozmiar klasy,
ktora jest wczesniej w pliku, przeciez bez problemu mozna odczytac
reszte pliku(plików) i ten rozmiar okreslic.
Seweryn Habdank-Wojewódzki
2007-06-05 00:14:30 UTC
Permalink
Witam
Post by Sulsa
On Mon, 04 Jun 2007 18:14:06 +0200
Post by Jakub Debski
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
klas w pliku, jest wiele jezykow w ktorych to nie ma znaczenia i
jest dobrze, wiec czemu w c++ cos takiego dalej jest?
nie chodzi o kolejność, ale o informacje na temat rozmiaru obiektu.
Bez tego nie mógłbyś przydzielić pamięci dla obiektu.
Języki w których nie jest to wymagane definiują w rzeczywistości
wskaźnik do obiektu, co wiąże się z tym, że odwołania do składowych
są wolniejsze niż w C++.
przeciez taki rozmiar mozna bez problemu okreslic, nie wiem czemu w c++
jest to zrobione tak prymitywnie ze znany jest jedyni rozmiar klasy,
ktora jest wczesniej w pliku, przeciez bez problemu mozna odczytac
reszte pliku(plików) i ten rozmiar okreslic.
Mylisz się. Qrczak napisał Ci, że dokładnie to co zrobiłeś nie ma sensu.

Primo są języki które zakładają, że nie chciałeś zrobić tego co zrobiłeś
i "zamieniają" to zadanie na wskaźniki (tylko Ty wskaźników nie widzisz).

Secundo rozmiar wskaźnika zawsze jest znany. Więc:

class B;

class A{
        B* b;    
};

class B{
        A* a;
};

Jest dobrze określonym bytem.

Zapisz sobie konkretnie kiedy A jest strukturą z intem, a B strukturą z
double, jakby wyglądała Twoja konstrukcja. A potem zrób to samo kiedy
zamienisz to na wskaźniki. Zobaczysz, że kiedy to są żywe obiekty, to klasa
A rośnie do nieskończoności i B też. Jak to są wskaźniki, to sprawa się
urywa na poziomie zapisu dwóch adresów.

A co do czytania wcześniej i określania rozmiaru to jet trochę co innego i
dokładnie Twój przykład pod to nie podejdzie, bo Ty masz dokładnie cykl i
nawet jakby kompilator to czytał w nieskończoność, to nic nie przeczyta.

U Ciebie jest tak:

class B;

class A{
        B b;

STOP - nie znam rozmiaru B, ale załóżmy, że moge czytać dalej.

}; <- ten punkt jest niekreślony w pamięci.

class B{
A a; < - tu też nie masz pojęcia o rozmiarze obiektu A, bo a jest
nieskończony (jego rozmiar jest nie ustalony.
};

Wiem że B skałda się z A

Zatem

class A{
class B{
A a;
} b;
}

STOP; nie znam rozmiaru A, ale załóżmy, że moge czytać dalej.

class A{
class B{
class A{
class B{
A a;
} b;
} a;
} b;
}

No i tak w nieskończoność, bo nigdy nie wiesz jaki jest rozmiar A. A może
wiesz? A tak na koniec jak definiujesz prymitywność czegoś w języku?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-06 19:18:09 UTC
Permalink
On Tue, 05 Jun 2007 02:14:30 +0200
Post by Seweryn Habdank-Wojewódzki
Mylisz się. Qrczak napisał Ci, że dokładnie to co zrobiłeś nie ma sensu.
WYRAZNIE NAPISALEM ze ten przyklad byl nie fortunny, jak ci to pomorze
to masz tu inny, w ktorym juz nie ma problemu z okresleniem rozmiaru
typu a jednak kompilator tego nie przepuszcza:

class B;

class A{
void a(B b){};
};

class B{
void a(A a){};
};

Wiec ponawiam pytanie, gdzie jest sensownosc nie dopuszczania do
takiego zapisu?
Seweryn Habdank-Wojewódzki
2007-06-06 21:28:29 UTC
Permalink
Witam
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest. Nadal B jest typem niekompletnym.
Post by Sulsa
class B;
class A{
void a(B b){};
Tu tworzysz funkcję w której wnętrzu (co prawda pustym) używasz kopii B, bo
parametr przekazujesz przez kopię, a nie przez referencję lub wskaźnik - B
jest nieznany.
Post by Sulsa
};
class B{
void a(A a){};
};
Wiec ponawiam pytanie, gdzie jest sensownosc nie dopuszczania do
takiego zapisu?
Kod poniżej kompiluje się, ponieważ funkcja "a" jest tylko deklarowana a nie
definiowana w klasie A. Definicja jest po tym jak zostanie określona klasa
B.

class B;

class A
{
void a(B b);
};

class B
{
void a(A a);
};

void A::a(B b){}
void B::a(A a){}

int main()
{

}

A rozwiązanie bardziej kompatybilne z językami "mniej prymitywnymi" jest
takie:

class B;

class A
{
void a(B & b) {};
};

class B
{
void a(A & a) {};
};

int main()
{

}

Zresztą różne jego wariancje są zalecane w języku C++, jako lepsze niż Twój
kod - niż kopiowanie, chyba że intencją autora funkcji/metody jest
kopiowanie wtedy musi użyć tego co napisałem jako poprawę Twojego kodu.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-06 22:01:13 UTC
Permalink
On Wed, 06 Jun 2007 23:28:29 +0200
Post by Seweryn Habdank-Wojewódzki
Witam
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest.
Oczywiście ze nie ma rozmiar obu typow wynosi 0.
Post by Seweryn Habdank-Wojewódzki
Nadal B jest typem niekompletnym.
no przeciez o to mi caly czas chodzi.
Seweryn Habdank-Wojewódzki
2007-06-07 09:57:34 UTC
Permalink
Witam
Post by Sulsa
On Wed, 06 Jun 2007 23:28:29 +0200
Witam
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest.
Oczywiście ze nie ma rozmiar obu typow wynosi 0.
A jak to uzasadnisz?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-07 11:23:15 UTC
Permalink
On Thu, 07 Jun 2007 11:57:34 +0200
Post by Seweryn Habdank-Wojewódzki
A jak to uzasadnisz?
nie maja rzadnych atrybutow wiec..
Sulsa
2007-06-07 11:25:25 UTC
Permalink
On Thu, 7 Jun 2007 13:23:15 +0200
Post by Sulsa
On Thu, 07 Jun 2007 11:57:34 +0200
Post by Seweryn Habdank-Wojewódzki
A jak to uzasadnisz?
nie maja rzadnych atrybutow wiec..
wiec maja rozmiar 1 (tu sie troche zdziwilem) ale to niewazne, istotne
jest ze ten rozmiar mozna okresilc.
Zbyszek Malec
2007-06-07 13:47:36 UTC
Permalink
Post by Sulsa
wiec maja rozmiar 1 (tu sie troche zdziwilem) ale to niewazne, istotne
jest ze ten rozmiar mozna okresilc.
Rozmiar 1 bierze się stąd, że jakoś trzeba adresować instancje.
--
Zbyszek Malec Ustronie 104
jid: ***@jid.pl
Seweryn Habdank-Wojewódzki
2007-06-07 13:50:06 UTC
Permalink
Post by Sulsa
On Thu, 7 Jun 2007 13:23:15 +0200
Post by Sulsa
On Thu, 07 Jun 2007 11:57:34 +0200
Post by Seweryn Habdank-Wojewódzki
A jak to uzasadnisz?
nie maja rzadnych atrybutow wiec..
wiec maja rozmiar 1 (tu sie troche zdziwilem) ale to niewazne, istotne
jest ze ten rozmiar mozna okresilc.
Nie.

Jeszcze raz prześledź swój program. W momencie konstrukcji funkcji
Post by Sulsa
class A{
    void a(B b){};
nie znasz rozmiaru B, bo on jest zależny od A, bo w funkcji
Post by Sulsa
class B{
void a(A a){};
Wystarczy pozostawić tylko deklaracje, definicje wyrzucić dalej i zadziała
już pisałem.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-08 00:51:31 UTC
Permalink
On Thu, 07 Jun 2007 15:50:06 +0200
Post by Seweryn Habdank-Wojewódzki
Nie.
Jeszcze raz prześledź swój program. W momencie konstrukcji funkcji
Post by Sulsa
class A{
    void a(B b){};
nie znasz rozmiaru B, bo on jest zależny od A, bo w funkcji
Niby w jaki sposob Rozmiar klasy A zalezy od B? Chyba nie myslisz ze
metody klasy wpywaja w jakis sposob na jej rozmiar?
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
class B{
void a(A a){};
Wystarczy pozostawić tylko deklaracje, definicje wyrzucić dalej i
zadziała już pisałem.
nie chodzi mi o to jak zadziala tylko czemu nie dziala w takis sposob,
trzymasz sie tego ze nie mozna orkeslic rozmiaru, a przeciez mozna
badajac dalej plik, ale nie sprzeczajmy sie o to dalej bo to do niczego
nie prowadzi.
Seweryn Habdank-Wojewódzki
2007-06-08 16:33:08 UTC
Permalink
Witam
Post by Sulsa
Post by Seweryn Habdank-Wojewódzki
Jeszcze raz prześledź swój program. W momencie konstrukcji funkcji
Post by Sulsa
class A{
void a(B b){};
nie znasz rozmiaru B, bo on jest zależny od A, bo w funkcji
Niby w jaki sposob Rozmiar klasy A zalezy od B? Chyba nie myslisz ze
metody klasy wpywaja w jakis sposob na jej rozmiar?
Nie chodzi o klasę A! Tutaj wołasz explicite kopiowanie obiektu klasy B.
Budujesz funkcję, która kopiuje obiekt klasy B. A gdzie masz jej rozmiar.
Wcześniej podałeś tylko i wyłącznie class B; Wyobraź sobie, jak kompilator
jakby miał czekać aż mu łaskawie podaż rozmiar? A może klasa B jest w innym
pliku? A może tej inny plik będzie kompilowany na 200, 500, 1000 plików.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Jedrzej Dudkiewicz
2007-06-07 10:27:50 UTC
Permalink
Post by Sulsa
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest.
Oczywiście ze nie ma rozmiar obu typow wynosi 0.
Prędzej 1.

JD
Sulsa
2007-06-07 11:24:32 UTC
Permalink
On Thu, 7 Jun 2007 12:27:50 +0200
Post by Jedrzej Dudkiewicz
Post by Sulsa
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest.
Oczywiście ze nie ma rozmiar obu typow wynosi 0.
Prędzej 1.
rzeczywiscie, dlaczego pusta klasa ma rozmiar 1?
Maciej Sobczak
2007-06-07 12:35:46 UTC
Permalink
Post by Sulsa
rzeczywiscie, dlaczego pusta klasa ma rozmiar 1?
1. Żeby można było zrobić tablicę takich obiektów.
2. Żeby wskaźnik do takiego obiektu miał na co wskazywać.

--
Maciej Sobczak
http://www.msobczak.com/
Piotr Wyderski
2007-06-09 00:27:09 UTC
Permalink
Post by Maciej Sobczak
1. Żeby można było zrobić tablicę takich obiektów.
Nie ma filozoficznych przeszkód, by zrobić tablicę z obiektów
o wielkości 0. Każdy z nich będzie miał adres base + n * 0. :-)
Post by Maciej Sobczak
2. Żeby wskaźnik do takiego obiektu miał na co wskazywać.
Może wskazywać gdziekolwiek, bo i tak nic z takiego
obiektu nie wyciągniesz. Natomiast odpowiedź na pytanie
brzmi: rozmiar jest niezerowy, bo C++ wymaga, by każda
instancja obiektu miała unikatowy adres.

Przy dziedziczeniu jednak kompilator często "przypomina sobie"
o pustości klasy bazowej i nie alokuje zbędnego pola -- to jest
właśnie EBO, czyli Empty Base Optimization.

Pozdrawiam
Piotr Wyderski
Marcin 'Qrczak' Kowalczyk
2007-06-09 06:55:33 UTC
Permalink
Post by Piotr Wyderski
Post by Maciej Sobczak
1. Żeby można było zrobić tablicę takich obiektów.
Nie ma filozoficznych przeszkód, by zrobić tablicę z obiektów
o wielkości 0. Każdy z nich będzie miał adres base + n * 0. :-)
Jest praktyczna przeszkoda w zaimplementowaniu odejmowania wskaźników
na elementy takiej tablicy i operatorów == i <.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Piotr Wyderski
2007-06-09 09:47:01 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Jest praktyczna przeszkoda w zaimplementowaniu
odejmowania wskaźników na elementy takiej tablicy
return ptrdiff_t(0);

:-)
Post by Marcin 'Qrczak' Kowalczyk
i operatorów ==
return true;
Post by Marcin 'Qrczak' Kowalczyk
i <.
return false;

Tyle, że w praktyce to jest zupełnie niepotrzebne (i do tego
łamie wymaganie unikatowości adresu), więc dyskusja jest
czysto akademicka.

Pozdrawiam
Piotr Wyderski
Marcin 'Qrczak' Kowalczyk
2007-06-09 11:22:15 UTC
Permalink
Post by Piotr Wyderski
Post by Marcin 'Qrczak' Kowalczyk
Jest praktyczna przeszkoda w zaimplementowaniu
odejmowania wskaźników na elementy takiej tablicy
return ptrdiff_t(0);
Nie spełnia warunku &a[i] - &a[j] == i-j, do którego powinno wystarczyć,
żeby a[i] i a[j] mieściły się w tablicy.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Maciej Sobczak
2007-06-09 19:00:47 UTC
Permalink
On 9 Cze, 02:27, "Piotr Wyderski"
Post by Piotr Wyderski
Post by Maciej Sobczak
1. Żeby można było zrobić tablicę takich obiektów.
Nie ma filozoficznych przeszkód, by zrobić tablicę z obiektów
o wielkości 0. Każdy z nich będzie miał adres base + n * 0. :-)
Już widzę iterację po takiej tablicy... :-)
Post by Piotr Wyderski
Post by Maciej Sobczak
2. Żeby wskaźnik do takiego obiektu miał na co wskazywać.
Może wskazywać gdziekolwiek, bo i tak nic z takiego
obiektu nie wyciągniesz.
Nie muszę wyciągać. Wystarczy, że zrobię delete p.

BTW - operator new, nawet z rozmiarem 0, musi zwrócić normalny adres.
Post by Piotr Wyderski
Natomiast odpowiedź na pytanie
brzmi: rozmiar jest niezerowy, bo C++ wymaga, by każda
instancja obiektu miała unikatowy adres.
Dokładnie o to chodzi.
Post by Piotr Wyderski
Przy dziedziczeniu jednak kompilator często "przypomina sobie"
o pustości klasy bazowej i nie alokuje zbędnego pola -- to jest
właśnie EBO, czyli Empty Base Optimization.
I bardzo dobrze, bardzo przydatne rzeczy można dzięki temu robić.

--
Maciej Sobczak
http://www.msobczak.com/
Sektor van Skijlen
2007-06-10 19:11:08 UTC
Permalink
Post by Piotr Wyderski
Post by Maciej Sobczak
1. Żeby można było zrobić tablicę takich obiektów.
Nie ma filozoficznych przeszkód, by zrobić tablicę z obiektów
o wielkości 0. Każdy z nich będzie miał adres base + n * 0. :-)
To przeiteruj mi cwaniaczku po takich obiektach, tak żeby rzeczywiście
była to ilość 'n' iteracji.
Post by Piotr Wyderski
Post by Maciej Sobczak
2. Żeby wskaźnik do takiego obiektu miał na co wskazywać.
Może wskazywać gdziekolwiek, bo i tak nic z takiego
obiektu nie wyciągniesz. Natomiast odpowiedź na pytanie
brzmi: rozmiar jest niezerowy, bo C++ wymaga, by każda
instancja obiektu miała unikatowy adres.
Tak, a to z kolei wynika z faktu, że jeśli zrobimy a == b,
a dostaniemy wynik false, to ma to oznaczać, że (pomijając przypadek,
gdy jedno z nich jest NULL lub ma wartość osobliwą) oba wskazują na
różne obiekty lub funkcje, a jeśli true, że oba wskazują na te same
obiekty lub funkcje.
Post by Piotr Wyderski
Przy dziedziczeniu jednak kompilator często "przypomina sobie"
o pustości klasy bazowej i nie alokuje zbędnego pola -- to jest
właśnie EBO, czyli Empty Base Optimization.
Dlatego, że podobiekt klasy bazowej nie podlega tym samym prawom, co
zwykłe obiekty. Podobiekt klasy bazowej nie jest nigdy uzyskiwany
inaczej, jak ze swojego nadobiektu, więc nie podlega prawom
zbiorników.
Sebastian Kaliszewski
2007-06-13 08:31:33 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
w ktorym juz nie ma problemu z okresleniem rozmiaru
Jest. Nadal B jest typem niekompletnym.
To jest akurat tylko i wyłącznie ograniczenie C++.
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
class B;
class A{
void a(B b){};
Tu tworzysz funkcję w której wnętrzu (co prawda pustym) używasz kopii B, bo
parametr przekazujesz przez kopię, a nie przez referencję lub wskaźnik - B
jest nieznany.
Nie masz jednak cyklicznej zależności sygnatury tej fukcji i typu B, nie ma
więc technicznego problemu z wygenerowaniem kodu (jednoprzebiegowość w
przypadku C++ jest bez znaczenia).
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
Wiec ponawiam pytanie, gdzie jest sensownosc nie dopuszczania do
takiego zapisu?
Kod poniżej kompiluje się, ponieważ funkcja "a" jest tylko deklarowana a nie
definiowana w klasie A. Definicja jest po tym jak zostanie określona klasa
B.
class B;
class A
{
void a(B b);
};
class B
{
void a(A a);
};
void A::a(B b){}
void B::a(A a){}
int main()
{
}
A rozwiązanie bardziej kompatybilne z językami "mniej prymitywnymi" jest
Te referencje nie są na nic potrzebne poza tym, że C++ ma standardowo takie
ograniczenie. To ograniczenie jest zresztą w języku tak skomplikowanym, z
szablonami i resztą naddatków nieuzasadnione technicznie -- uzasadnione jest
tylko historycznie -- tak zawsze było, wszyscy się przyzwyczaili i nie ma po
co zmieniać. Zwłąszcza że obchodzi się to przez wyjęcie definicji metod
(po)za definicję samej klasy.

pzdr
\SK
Seweryn Habdank-Wojewódzki
2007-06-13 09:44:42 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
class B;
class A{
void a(B b){};
Tu tworzysz funkcję w której wnętrzu (co prawda pustym) używasz kopii B,
bo parametr przekazujesz przez kopię, a nie przez referencję lub wskaźnik
- B jest nieznany.
Nie masz jednak cyklicznej zależności sygnatury tej fukcji i typu B, nie
ma więc technicznego problemu z wygenerowaniem kodu (jednoprzebiegowość w
przypadku C++ jest bez znaczenia).
Możesz to jakoś pokazać.

{} oznaczają tyle co

{
B tmp = b;
// tutaj używając b tak naprawdę pracujesz na kopii b czyli tmp.
// Czyli B musi być znane, bo musi zostać wykonana kopia.
// W szczególności np. memcpy, które musi znać rozmiar.
}
Post by Sebastian Kaliszewski
Te referencje nie są na nic potrzebne poza tym, że C++ ma standardowo
takie ograniczenie.
To ograniczenie jest zresztą w języku tak
skomplikowanym, z szablonami i resztą naddatków nieuzasadnione technicznie
-- uzasadnione jest tylko historycznie -- tak zawsze było, wszyscy się
przyzwyczaili i nie ma po co zmieniać. Zwłąszcza że obchodzi się to przez
wyjęcie definicji metod (po)za definicję samej klasy.
To też proszę rozwiń, co się dzieje jeśli masz klasę w pliku innym? Jak by
to wszystko było takie proste, to już dawno by to zrobili, bo przecież jest
wygoda. Pomijam aspekt że możesz kompilować pliki nie zależnie i pomijam
kwestie takie, że w "lepszych" językach ludzie używają
referencji/wskaźników i nikt nie płacze i nie dziwi się, że coś jest nie
tak (bo tam nic nie może być "nie tak", jak domyślnie pracujesz na ref czy
ptr).

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sebastian Kaliszewski
2007-06-13 10:19:44 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Post by Sulsa
class B;
class A{
void a(B b){};
Tu tworzysz funkcję w której wnętrzu (co prawda pustym) używasz kopii B,
bo parametr przekazujesz przez kopię, a nie przez referencję lub wskaźnik
- B jest nieznany.
Nie masz jednak cyklicznej zależności sygnatury tej fukcji i typu B, nie
ma więc technicznego problemu z wygenerowaniem kodu (jednoprzebiegowość w
przypadku C++ jest bez znaczenia).
Możesz to jakoś pokazać.
Co mam pokazywać? B jest zdefiniowane przecież poniżej w *tej samej*
jednostce kompilacji. Nie ma problemu by kompilację zrobić dwuprzebiegowo --
i tak jest robiona dwu lub więcej przebiegowo w większości cokolwiek wartych
kompilatorów.
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
Te referencje nie są na nic potrzebne poza tym, że C++ ma standardowo
takie ograniczenie.
To ograniczenie jest zresztą w języku tak
skomplikowanym, z szablonami i resztą naddatków nieuzasadnione technicznie
-- uzasadnione jest tylko historycznie -- tak zawsze było, wszyscy się
przyzwyczaili i nie ma po co zmieniać. Zwłąszcza że obchodzi się to przez
wyjęcie definicji metod (po)za definicję samej klasy.
To też proszę rozwiń, co się dzieje jeśli masz klasę w pliku innym?
A co ma się dziać
Post by Seweryn Habdank-Wojewódzki
Jak by
to wszystko było takie proste,
To jest proste. Zapewniam cię.
Post by Seweryn Habdank-Wojewódzki
to już dawno by to zrobili, bo przecież jest
wygoda.
Taaaa. Standard jest tak szyyyybkooooo rooooozwiiiiiijaaaaaanyyyyyyyyyyy.

BTW ci co chcieli to zrobili (patrz BCB).
Post by Seweryn Habdank-Wojewódzki
Pomijam aspekt że możesz kompilować pliki nie zależnie
To nie ma *absolutnie* nic do rzeczy.
Post by Seweryn Habdank-Wojewódzki
i pomijam
kwestie takie, że w "lepszych" językach ludzie używają
referencji/wskaźników i nikt nie płacze i nie dziwi się, że coś jest nie
tak (bo tam nic nie może być "nie tak", jak domyślnie pracujesz na ref czy
ptr).
To wynika z zupełnie innych powodów.

BTW.

Problem jest czysto historycznym ograniczeniem. Zresztą dlaczego, np to się
kompiluje:

struct foo
{
void bar() { baz b = 1; }

typedef int baz;
};


a to nie:


void bar() { baz b = 1; }

typedef int baz;



Widzisz, powodow technicnych nie ma absolutnie żadnych. To jest zaszłość
czystej postaci.

pzdr
\SK
Seweryn Habdank-Wojewódzki
2007-06-13 10:21:40 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Możesz to jakoś pokazać.
Co mam pokazywać? B jest zdefiniowane przecież poniżej w *tej samej*
jednostce kompilacji. Nie ma problemu by kompilację zrobić dwuprzebiegowo
-- i tak jest robiona dwu lub więcej przebiegowo w większości cokolwiek
wartych kompilatorów.
Czyli. Które kompilatory tak robią? Czy biegają tylko po jednym pliku, czy
po wszystkich includach w obrębie kompilacji?
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
To też proszę rozwiń, co się dzieje jeśli masz klasę w pliku innym?
A co ma się dziać
Ni po za faktem, ze zamiast biegać 2 razy przez 100 "linii", biegasz dwa
razy przez 10000 "linii"
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
to już dawno by to zrobili, bo przecież jest
wygoda.
Taaaa. Standard jest tak szyyyybkooooo rooooozwiiiiiijaaaaaanyyyyyyyyyyy.
BTW ci co chcieli to zrobili (patrz BCB).
A nadal tak mają? Tak mieli w 2001, teraz to nie wiem.
Post by Sebastian Kaliszewski
Widzisz, powodow technicnych nie ma absolutnie żadnych. To jest zaszłość
czystej postaci.
E tam. Klasy struktury nie rozciągasz na wiele plików - tak mi się wydaje.
Chyba żaden język tego nie daje. Chyba że w C++ zrobisz tak:

class Foo
{
#include "foo.inlc"
};

Ale za taki coding-style to się strzela.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Seweryn Habdank-Wojewódzki
2007-06-07 10:03:57 UTC
Permalink
Witam

Może jeszcze inaczej.
Post by Sulsa
class B;
class A{
void a(B b){};
To powyżej jest mniej więcej takie:

void a(B orig)
{
B b = orig;
};

I kompilator w tym miejscu nie wie jaki rozmiar ma B, a po cichu zbudowałeś
obiekt typu B.
Post by Sulsa
};
class B{
void a(A a){};
To samo zresztą tutaj.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-07 11:22:38 UTC
Permalink
On Thu, 07 Jun 2007 12:03:57 +0200
Post by Seweryn Habdank-Wojewódzki
void a(B orig)
{
B b = orig;
};
I kompilator w tym miejscu nie wie jaki rozmiar ma B, a po cichu
zbudowałeś obiekt typu B.
wiem ze nie wie i wlasnie o to sie caly czas pytam: dlaczego w 21 wieku
kompilator nie moze sobie zrobic dwoch przebiegow rzeby ten rozmiar
okreslic(jest to mozliwe poza przypadkiem, ktory podalem w pierwszym
poscie) . Czym szanowny komitet kierowal sie pozostawiajac taki
archaizm w jezyku, rozumiem ze w latach siedemdziesiatych moglo to
niepotrzebnie wydluzac kapilacje, ale teraz nikt by tego nie zauwazyl,
a wygoda programowania jest duzo wazniejsza aby jezyk przetrwal.
Maciej Sobczak
2007-06-07 12:46:29 UTC
Permalink
Post by Sulsa
Post by Seweryn Habdank-Wojewódzki
void a(B orig)
{
B b = orig;
};
I kompilator w tym miejscu nie wie jaki rozmiar ma B, a po cichu
zbudowałeś obiekt typu B.
wiem ze nie wie i wlasnie o to sie caly czas pytam: dlaczego w 21 wieku
kompilator nie moze sobie zrobic dwoch przebiegow rzeby ten rozmiar
okreslic(jest to mozliwe poza przypadkiem, ktory podalem w pierwszym
poscie).
To nie jest tylko kwestia rozmiaru, ale też np. tego, jak działa
konstruktor kopiujący.
I czy w ogóle jest tam jakiś dostępny konstruktor kopiujący.

Deklarując klasę B dajesz kompilatorowi do zrozumienia, że *jest* taka
klasa, a nie jakie są szczegóły jej implementacji. Skoro tak, to nie
posługuj się w dalszych kontekstach operacjami, które tych szczegółów
wymagają.
Post by Sulsa
Czym szanowny komitet kierowal sie
Złe pytanie.
Dobre pytanie: czym szanowny programista kierował się wykonując
operacje wymagające znajomości szczegółów implementacyjnych czegoś i
jednocześnie ukrywając te szczegóły za deklaracją niekompletnego typu?
Post by Sulsa
pozostawiajac taki
archaizm
Dont łory, to nie jest jedyny taki język.
Post by Sulsa
w jezyku, rozumiem ze w latach siedemdziesiatych moglo to
niepotrzebnie wydluzac kapilacje, ale teraz nikt by tego nie zauwazyl,
a wygoda programowania jest duzo wazniejsza aby jezyk przetrwal.
Wygoda programowania polega na tym, że można oddzielić w czasie i
przestrzeni proces tworzenia modułów, jeśli nie korzystają z siebie
nawzajem w sposób wymagający wzajemnej znajomości swoich szczegółów
implementacyjnych.
Faktem jest, że przy "Hello World" spektakularnych zysków nie widać,
ale też nikt nie każe takich programów pisać w C++.

I przede wszystkim - przetrwanie języka nie zależy od tego, czy będzie
wspierał właśnie *taką* koncepcję "wygody".

--
Maciej Sobczak
http://www.msobczak.com/
Sulsa
2007-06-07 13:20:20 UTC
Permalink
On Thu, 07 Jun 2007 05:46:29 -0700
Post by Maciej Sobczak
To nie jest tylko kwestia rozmiaru, ale też np. tego, jak działa
konstruktor kopiujący.
I czy w ogóle jest tam jakiś dostępny konstruktor kopiujący.
Ale to wszystko da sie okreslic. Ktorys z grupowiczow podal przyklad
kompilatora borladna, ktory to wlasnie robil.
Post by Maciej Sobczak
Deklarując klasę B dajesz kompilatorowi do zrozumienia, że *jest* taka
klasa, a nie jakie są szczegóły jej implementacji. Skoro tak, to nie
posługuj się w dalszych kontekstach operacjami, które tych szczegółów
wymagają.
ale to da sie okreslic wiec wogole nie powinien sie do tego kompilator
czepiac.
Post by Maciej Sobczak
Post by Sulsa
Czym szanowny komitet kierowal sie
Złe pytanie.
Dobre pytanie: czym szanowny programista kierował się wykonując
operacje wymagające znajomości szczegółów implementacyjnych czegoś i
jednocześnie ukrywając te szczegóły za deklaracją niekompletnego typu?
To opisalem dalej, nawiazujac jescze do tego pytania to tak mozna by
odpowiedziec na kazda slabosc jezyka, bo czym programista kierowal sie
chcac napisac program w sposob latwiejszy/przyjemniejszy - odpowiedz
jest zawarta w pytaniu. A problem ktory opisalem nie wydaje sie trudny
do rozwiazania, wiec dziwie sie ze taki archaizm jeszcze pozostal -
mysle ze usuniecie tego nie spowodowalo by nawet zadnych problemow ze
wsteczna kompatybilnoscia.
Post by Maciej Sobczak
Post by Sulsa
pozostawiajac taki
archaizm
Dont łory, to nie jest jedyny taki język.
Wygoda programowania polega na tym, że można oddzielić w czasie i
przestrzeni proces tworzenia modułów, jeśli nie korzystają z siebie
nawzajem w sposób wymagający wzajemnej znajomości swoich szczegółów
implementacyjnych.
Faktem jest, że przy "Hello World" spektakularnych zysków nie widać,
ale też nikt nie każe takich programów pisać w C++.
I przede wszystkim - przetrwanie języka nie zależy od tego, czy będzie
wspierał właśnie *taką* koncepcję "wygody".
Wygoda programowania to duzo wiecej niz napisales, a mi ten szczegol o
ktorym napisalem zabral z godzine przestawiania roznych klas po
plikach, zeby usatysfakcjonowac kompilator i zeby to wszystko bylo
jakos logicznie porozmieszczane. Wknocu ZOSTALEM ZMUSZONY przez
kompilator do wybrania ulozenia klas w plikach takiego jak nie
chcialem, a tak nie powinno byc, jezyk powinien dawac mi swobode a nie
mnie ograniczac - i tu nie ma zadnych tlumaczen ze to w jakis sposob
bylo by niebezpieczne, nieoptymalne - nikt narazie takich przykladow
nie wskazal.
Seweryn Habdank-Wojewódzki
2007-06-07 14:17:36 UTC
Permalink
Witam
Post by Sulsa
Post by Maciej Sobczak
To nie jest tylko kwestia rozmiaru, ale też np. tego, jak działa
konstruktor kopiujący.
I czy w ogóle jest tam jakiś dostępny konstruktor kopiujący.
Ale to wszystko da sie okreslic. Ktorys z grupowiczow podal przyklad
kompilatora borladna, ktory to wlasnie robil.
Kolego, a co ma kompilator wspólnego z komitetem. Jeden przebieg to prywatna
sprawa np. gcc. To też się dotyczy kompilacji kodu języka C.
Wynika to z tego, że zysk z wielu przebiegów jest mizerny, w stosunku do
straty na czasie kompilacji.
Post by Sulsa
Post by Maciej Sobczak
Deklarując klasę B dajesz kompilatorowi do zrozumienia, że *jest* taka
klasa, a nie jakie są szczegóły jej implementacji. Skoro tak, to nie
posługuj się w dalszych kontekstach operacjami, które tych szczegółów
wymagają.
ale to da sie okreslic wiec wogole nie powinien sie do tego kompilator
czepiac.
Ma to wielkie znaczenie. Bo mając header osobno i implementacje osobno nie
możesz nic powiedzieć - często to nie jest potrzebne.
Post by Sulsa
Post by Maciej Sobczak
Post by Sulsa
Czym szanowny komitet kierowal sie
Złe pytanie.
Dobre pytanie: czym szanowny programista kierował się wykonując
operacje wymagające znajomości szczegółów implementacyjnych czegoś i
jednocześnie ukrywając te szczegóły za deklaracją niekompletnego typu?
To opisalem dalej, nawiazujac jescze do tego pytania to tak mozna by
odpowiedziec na kazda slabosc jezyka
Jaka to słabość języka? Jakie języki nie mają tej słabości dając
jednocześnie opcję separowania kodu wykonywalnego.
Post by Sulsa
, bo czym programista kierowal sie
chcac napisac program w sposob latwiejszy/przyjemniejszy
Co tu jest łatwiejsze? W każdym miejscu popełniłeś błędy.
1. Zamiast posługiwać się referencją, kopiujesz obiekty
2. Zamiast separować deklaracje od definicji wszystko pakujesz do klasy,
która za 5 takich funkcji będzie nie czytelna.
3. Wyobraź sobie, że chcesz nie pokazywać kodu programu, ale chcesz swoja
klasę udostępnić, to co robisz, jak wszystko wpakowałeś w jeden plik?
4. Wyobraź sobie, że masz 500 takiech headerów zawierających wszyskto w
środku, kazda zmiania w dowolnym pliku powoduje, że musisz całość
przekompilować - to znaczy zawsze plik główny, ale on pociąga za sobą
kompilację całości kodu.
Post by Sulsa
- odpowiedz
jest zawarta w pytaniu. A problem ktory opisalem nie wydaje sie trudny
do rozwiazania, wiec dziwie sie ze taki archaizm jeszcze pozostal -
mysle ze usuniecie tego nie spowodowalo by nawet zadnych problemow ze
wsteczna kompatybilnoscia.
Nie bo wielo-przebiegowość daje popalić, a wygoda pisania podobnych klas
jest żadna. Zresztą z tego powodu wieloprzebiegowość nie jest stosowana
ogólnie.
Post by Sulsa
Post by Maciej Sobczak
I przede wszystkim - przetrwanie języka nie zależy od tego, czy będzie
wspierał właśnie *taką* koncepcję "wygody".
Wygoda programowania to duzo wiecej niz napisales, a mi ten szczegol o
ktorym napisalem zabral z godzine przestawiania roznych klas po
plikach
Bo masz zły kod. jakbyś użył referencji/wskaźnika to by nie było kłopotu.
Post by Sulsa
, zeby usatysfakcjonowac kompilator
kompilator to nie jest język.
Post by Sulsa
i zeby to wszystko bylo
jakos logicznie porozmieszczane. Wknocu ZOSTALEM ZMUSZONY przez
kompilator do wybrania ulozenia klas w plikach takiego jak nie
chcialem, a tak nie powinno byc, jezyk powinien dawac mi swobode a nie
mnie ograniczac - i tu nie ma zadnych tlumaczen ze to w jakis sposob
bylo by niebezpieczne, nieoptymalne - nikt narazie takich przykladow
nie wskazal.
Nie chcę wiedzieć jaki bałagan masz w kodzie, jak robisz takie błędy
programistyczne. Zresztą napisałem już pytanie, jaki to projekt, że
potrzeba tak silny zależności? Normalnie nie potrzeba. Ale jesteś
mądrzejszy, no więc szukaj mądrzejszego kompilatora niż gcc.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Maciej Sobczak
2007-06-07 20:36:37 UTC
Permalink
Post by Sulsa
Post by Maciej Sobczak
To nie jest tylko kwestia rozmiaru, ale też np. tego, jak działa
konstruktor kopiujący.
I czy w ogóle jest tam jakiś dostępny konstruktor kopiujący.
Ale to wszystko da sie okreslic. Ktorys z grupowiczow podal przyklad
kompilatora borladna, ktory to wlasnie robil.
I co - robi to również wtedy, gdy definicji klasy jeszcze *nie ma*?
No to niezły jest ten kompilator Borlanda - Chuck Norris wśród
kompilatorów.
Post by Sulsa
Post by Maciej Sobczak
Deklarując klasę B dajesz kompilatorowi do zrozumienia, że *jest* taka
klasa, a nie jakie są szczegóły jej implementacji. Skoro tak, to nie
posługuj się w dalszych kontekstach operacjami, które tych szczegółów
wymagają.
ale to da sie okreslic
Nie da się, bo w tym miejscu nie wiadomo jeszcze, gdzie szukać
definicji klasy.
Post by Sulsa
To opisalem dalej, nawiazujac jescze do tego pytania to tak mozna by
odpowiedziec na kazda slabosc jezyka, bo czym programista kierowal sie
chcac napisac program w sposob latwiejszy/przyjemniejszy - odpowiedz
jest zawarta w pytaniu.
To nie jest kwestia tego, czy sposób jest łatwiejszy/przyjemniejszy.
To jest kwestia tego, czy walenie w klawiaturę było poprzedzone jakimś
etapem projektowym. Gdyby był, to nie miałbyś modułów, które mają
silne cykliczne zależności - a wtedy Twój problem w ogóle by nie
wystąpił.
Post by Sulsa
A problem ktory opisalem nie wydaje sie trudny
do rozwiazania
Oczywiście, że nie. Wystarczy zrobić sensowny układ modułów i po
problemie.
Post by Sulsa
Wknocu ZOSTALEM ZMUSZONY przez
kompilator do wybrania ulozenia klas w plikach takiego jak nie
chcialem
Może to co chciałeś nie było właściwe?
Post by Sulsa
a tak nie powinno byc, jezyk powinien dawac mi swobode
Język daje Ci ogromną swobodę podziału programu na moduły, które będą
mogły być kompilowane niezależnie.

--
Maciej Sobczak
http://www.msobczak.com/
Zbyszek Malec
2007-06-07 20:44:49 UTC
Permalink
Post by Maciej Sobczak
Język daje Ci ogromną swobodę podziału programu na moduły, które będą
mogły być kompilowane niezależnie.
W tym przypadku się z tobą zgadzam, taka cykliczna zależność to nic
dobrego, ale w ogólności nie zgadzam się, że C++ daje ogromną swobodę
podziału programu na moduły. Czekam z utęsknieniem na jakąś sensowną
pakietyzację w C++.
--
Zbyszek Malec Ustronie 104
jid: ***@jid.pl
Maciej Sobczak
2007-06-07 20:52:48 UTC
Permalink
Post by Zbyszek Malec
w ogólności nie zgadzam się, że C++ daje ogromną swobodę
podziału programu na moduły.
Swobodę daje *ogromną*, gorzej ze wsparciem. ;-)
Post by Zbyszek Malec
Czekam z utęsknieniem na jakąś sensowną
pakietyzację w C++.
O, jest szansa na ciekawy wątek. :-)
Czego brakuje w obecnych mechanizmach?

(uwaga: nie twierdzę, że niczego.)

--
Maciej Sobczak
http://www.msobczak.com/
Sektor van Skijlen
2007-06-10 18:43:36 UTC
Permalink
Post by Maciej Sobczak
Post by Zbyszek Malec
w ogólności nie zgadzam się, że C++ daje ogromną swobodę
podziału programu na moduły.
Swobodę daje *ogromną*, gorzej ze wsparciem. ;-)
Post by Zbyszek Malec
Czekam z utęsknieniem na jakąś sensowną
pakietyzację w C++.
O, jest szansa na ciekawy wątek. :-)
Czego brakuje w obecnych mechanizmach?
(uwaga: nie twierdzę, że niczego.)
Na przykład, przydałoby się coś, co pozwalałoby uniknąć preprocesora z
#include :).

Przede wszystkim problem z C++ polega na tym, że pakietyzacja w tym
wykonaniu jest bazowana na tym, co posiada język C (oczywiście to
niewiele zmienia, że jest to jedyny model wiązania modułów na poziomie
systemowym w popularnych systemach operacyjnych). To polega na tym, że
posiadamy jedynie pliki nagłówkowe, które mogą zawierać cokolwiek, a
następnie w plikach *.o mogą się zawierać tylko i wyłącznie definicje
obiektów POD oraz skompilowane wersje funkcji plus odwołania do innych
symboli - wszystko określone odpowiednią nazwą symbolu. Czyli podlegać
wiązaniu mogą tylko obiekty "płaskie" oraz funkcje. Cała reszta musi
jakoś się do tego upchnąć. Nie mogą zatem podlegać wiązaniu wzorce,
czy klasy.

To, co by się przydało na dobry początek, to takie pliki *.o, które
potrafiłyby zawierać w sobie definicje wzorców i klas. Tak, żeby można
było się do nich odwoływać w trakcie kompilacji, czy żeby nawet to
rozwiązywał linker. Nie mówię, że należy się pozbyć plików
nagłówkowych (zresztą to byłoby niemożliwe, jeśli nie chcemy
całkowicie uniemożliwiać włączania bibliotek C) - tą koncepcję można
wykorzystać do jawnego dołączania odpowiednich elementów określonych
bibliotek.

Oczywiście byłby tutaj problem ze zrobieniem na bazie tej koncepcji
wiązania dynamicznego. Nie bardzo sobie wyobrażam np. w jaki sposób
wzorzec w dll-ce miałby się skonkretyzować podczas ładowania - ale
niewykluczone, że to jest do rozwiązania w jakiś sposób. W każdym
razie, na dobry początek wystarczy, żeby mogło się to wiązać
statycznie.

Co np. uważam, że jest niepotrzebnie wsadzane do plików nagłówkowych i
ta konieczność wynika tylko z ograniczeń:
- klasy
- funkcje inline
- wzorce (w sensie, pełne ich definicje)

Spróbujmy zrobić małe porównanie. Jak wiemy, jedną z możliwości
symulowania klasy w języku C jest zdefiniowanie wszystkiego, co
potrzebne, w jednym pliku *.c. Zmienne globalne z odpowiadającym
extern w *.h to publiczne zmienne statyczne. Zmienne 'static' to
prywatne zmienne statyczne. Funkcje bez żadnych specjalnych
właściwości to metody statyczne. Jeśli ta klasa ma mieć instancje, to
powinna mieć swoją własną strukturę, która jest zdefiniowana w pliku
*.c, a w *.h posiada jedynie deklarację. Konstruktorem byłaby funkcja,
która zwraca taki obiekt przez wskaźnik na ową strukturę. Metody
takiej klasy to funkcje, które przyjmują ten wskaźnik jako pierwszy
argument. Jeśli metoda nie ma swojego nagłówka w pliku *.h, to jest
prywatna.

Jak więc definicja takiej niby klasy będzie zatem wyglądać w języku C?

Plik *.h musi zawierać:
- extern do zmiennych (publiczne pola statyczne)
- extern do funkcji (publiczne metody zwykłe i statyczne)
- deklarację struktury (żeby mieć nazwę typu)

Dostęp do innych informacji - takich np. jak rozmiar obiektu - można
dostarczyć również za pomocą odpowiedniej funkcji, jeśli twórca klasy
tak sobie zażyczy.

Jeśli ktoś chce przykład czegoś istniejącego, stworzonego wedle tej
zasady, proszę zajrzeć sobie do <dirent.h>.

Odnosząc to teraz do C++, w pliku nagłówkowym powinno wystarczyć
zadeklarowanie:
- metod publicznych i chronionych
- pól publicznych i chronionych (jako bonus - w wersji C akurat nie
jest to możliwe; tam dostęp do pól trzeba by dorobić dodatkowo za
pomocą odpowiednich metod)
- zapowiedzi wzorców - funkcje tylko same deklaracje, a klasy wedle
schemtatu powyżej

Cała reszta powinna się móc zawrzeć w plikach *.cc

Niestety zastanawiając się nad tym modelem przychodzi mi do głowy
jedynie takie coś: albo pliki nagłówkowe (i pełna definicja klasy w
pliku nagłówkowym wyłącznie), albo pełna definicja klasy w pliku *.cc
(i bez pliku nagłówkowego).
Seweryn Habdank-Wojewódzki
2007-06-10 18:59:21 UTC
Permalink
Witam
Post by Sektor van Skijlen
Cała reszta musi
jakoś się do tego upchnąć. Nie mogą zatem podlegać wiązaniu wzorce,
czy klasy.
Dla klasy to masz rację. I juz kilka razy podnosiły się głosy o konieczność
ustandaryzowania ABI.

Ale jak wyobrażasz sobie, aby w języku kompilowanym można było
przekazać "wzorzec" - o ile masz na myśli szablon, bo w sumie to nie wiem
co to jest wzorzec.
Post by Sektor van Skijlen
Oczywiście byłby tutaj problem ze zrobieniem na bazie tej koncepcji
wiązania dynamicznego. Nie bardzo sobie wyobrażam np. w jaki sposób
wzorzec w dll-ce miałby się skonkretyzować podczas ładowania - ale
niewykluczone, że to jest do rozwiązania w jakiś sposób. W każdym
razie, na dobry początek wystarczy, żeby mogło się to wiązać
statycznie.
Rozwiązanie statyczne jest dla klas. Dla wzorców i tak musisz mieć kod
wzorca, bo niby jak generować nowe konkretyzacje, błędy, czy coś.

Na poziomie dynamicznym jest problem zarówno z klasami jak i z szablonami.
Ale np. na linuxie nie jest to brzydkie. Bo wystarczy mieć napisany loader
oraz fabrykę. Muszą być separowane. Loader powinien być singletonem, ale
możliwym do stworzenia nie koniecznie w czasie statycznej inicjalizacji
programu, ponieważ, kiedy soft nie wchodzi w daną gałąź zadań nie musi
ładować danej biblioteki. Do tego bardziej hardkorowe zadanie, to takie
kiedy program sam dla siebie tworzy .so, które następnie po skompilowaniu
ładuje sam dla siebie.

Fabryka to jest zaledwie kilkanaście linii kodu. Można nawet ją napisać
generycznie, tyle, że IMHO wymagane jest ręczne pisanie specjalizacji, ale
to jest taki banał, że można sobie machnąć generator kodu, bądź poszyć to
jakimiś makrami.
Post by Sektor van Skijlen
Co np. uważam, że jest niepotrzebnie wsadzane do plików nagłówkowych i
- klasy
- funkcje inline
- wzorce (w sensie, pełne ich definicje)
Moja wyobraźnia jest maleńka. Jak nie mając kodu chcesz rozwijać "wzorzec"?
Post by Sektor van Skijlen
- zapowiedzi wzorców - funkcje tylko same deklaracje, a klasy wedle
schemtatu powyżej
Może słowo extern dla szablonów wejdzie w użycie.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sektor van Skijlen
2007-06-10 19:25:17 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Witam
Post by Sektor van Skijlen
Cała reszta musi
jakoś się do tego upchnąć. Nie mogą zatem podlegać wiązaniu wzorce,
czy klasy.
Dla klasy to masz rację. I juz kilka razy podnosiły się głosy o konieczność
ustandaryzowania ABI.
Ale jak wyobrażasz sobie, aby w języku kompilowanym można było
przekazać "wzorzec" - o ile masz na myśli szablon, bo w sumie to nie wiem
co to jest wzorzec.
Zależy co i jak kompilujesz. Postać finalna najogólniejsza, czyli plik
wykonywalny, powinien zawierać, owszem, wyłącznie kod binarny w
formacie rozpoznawalnym przez system. Ale plik *.o? Przecież to tylko
plik składowy. Co za różnica, jak on będzie wyglądał i co będzie
zawierał? Ma zawierać po prostu wszystkie te rzeczy, które następnie
linker będzie mógł ("arbitralnie") poskładać do kupy i wyprodukować
plik wykonywalny.

Z biblioteką sprawa ma się trochę inaczej, ale niewiele.
Post by Seweryn Habdank-Wojewódzki
Rozwiązanie statyczne jest dla klas. Dla wzorców i tak musisz mieć kod
wzorca, bo niby jak generować nowe konkretyzacje, błędy, czy coś.
Wzorzec można skompilować do postaci odpowiedniego prostego kodu,
który następnie uzupełni się odpowiednimi odwołaniami i wstawkami, gdy
jest gdzieś kod zależny od parametrów wzorców lub innych wzorców. Nie
potrzebujesz kodu źródłowego, żeby skonkretyzować wzorzec -
potrzebujesz definicji wzorca w postaci zrozumiałej przez narzędzie,
które będzie ten wzorzec konkretyzować.
Post by Seweryn Habdank-Wojewódzki
Post by Sektor van Skijlen
Co np. uważam, że jest niepotrzebnie wsadzane do plików nagłówkowych i
- klasy
- funkcje inline
- wzorce (w sensie, pełne ich definicje)
Moja wyobraźnia jest maleńka. Jak nie mając kodu chcesz rozwijać "wzorzec"?
Rozwijać go z czego innego? Rzeczywiście twoja wyobraźnia jest
maleńka. Już od dłuższego czasu kompilatory posiadają coś, co się
nazywa "precompiled headers". Myślisz, że dla jakiego języka to
powstało? Dla C, w którym parsowanie pliku nagłówkowego to myk i
gotowe?

Ta funkcjonalność już jest. Jeśli możemy zamiast pliku *.h użyć pliku
*.gch (a wzorce, jak wiadomo, definiuje się w pliku *.h), to znaczy że
nie potrzebujemy kodu źródłowego wzorca, żeby wygenerować
konkretyzację wzorca.

Chyba że - podobnie jak pp. Lewandowski i Karpierz - uważasz, że
wzorce w C++ to taki inny makrogenerator.
Post by Seweryn Habdank-Wojewódzki
Post by Sektor van Skijlen
- zapowiedzi wzorców - funkcje tylko same deklaracje, a klasy wedle
schemtatu powyżej
Może słowo extern dla szablonów wejdzie w użycie.
Myślę, że wejdzie, zresztą w tej chwili to już jest tylko stwierdzenie
faktu. W gcc ta funkcjonalność istnieje od dawna i bez extern.
Seweryn Habdank-Wojewódzki
2007-06-10 19:46:45 UTC
Permalink
Witam
Post by Sektor van Skijlen
Zależy co i jak kompilujesz. Postać finalna najogólniejsza, czyli plik
wykonywalny, powinien zawierać, owszem, wyłącznie kod binarny w
formacie rozpoznawalnym przez system. Ale plik *.o? Przecież to tylko
plik składowy. Co za różnica, jak on będzie wyglądał i co będzie
zawierał? Ma zawierać po prostu wszystkie te rzeczy, które następnie
linker będzie mógł ("arbitralnie") poskładać do kupy i wyprodukować
plik wykonywalny.
Ale linker nie kompiluje. Żebyśmy jednak nie gadali a muzo, proponuję
oddzielić kwestie klas i kwestię szablonów.

Klasy jak powkładasz do pliku .o to są odzyskiwalne w czystej formie C++.
Inna sprawa, że gcc ma inne ABI dla serii 3.x i dla 4.x (nie pamiętam
dokładnie gdzie są zmiany). Ale pomijając ten detal jak zrobisz sobie .o to
ono jest pięknie czytelne.

Mam u siebie na kompie trochę maleńkich utilków, które mam pokompilowana do
plików .o.
Potem kiedy coś potrzebuję wyciągnąć, to biorę sobie takie pliki .o i pakuję
do jednego .a i statycznie ładuję do programu. Nic nie zmieniam. To
oczywiście nie działa dla szablonów, ale jak pisałem to jest inna inszość.
Post by Sektor van Skijlen
Z biblioteką sprawa ma się trochę inaczej, ale niewiele.
IMHO jest duża różnica. bo niestety .so nie ma ABI dla C++ i musisz to
obejść, ale nie jest to paskudne.
Post by Sektor van Skijlen
Post by Seweryn Habdank-Wojewódzki
Rozwiązanie statyczne jest dla klas. Dla wzorców i tak musisz mieć kod
wzorca, bo niby jak generować nowe konkretyzacje, błędy, czy coś.
Wzorzec można skompilować do postaci odpowiedniego prostego kodu,
który następnie uzupełni się odpowiednimi odwołaniami i wstawkami, gdy
jest gdzieś kod zależny od parametrów wzorców lub innych wzorców.
Wystarczy, że zabawisz się sizeof(T) i mogą być kłopoty. Tak mi się wydaje.
A zabawy z sizeof(T) nie są pozbawione sensu.
Post by Sektor van Skijlen
Nie
potrzebujesz kodu źródłowego, żeby skonkretyzować wzorzec -
potrzebujesz definicji wzorca w postaci zrozumiałej przez narzędzie,
które będzie ten wzorzec konkretyzować.
Rozwijać go z czego innego? Rzeczywiście twoja wyobraźnia jest
maleńka. Już od dłuższego czasu kompilatory posiadają coś, co się
nazywa "precompiled headers". Myślisz, że dla jakiego języka to
powstało? Dla C, w którym parsowanie pliku nagłówkowego to myk i
gotowe?
Hmm...?

A możesz mi zapodać przykład kiedy to istotnie działa. Ale chodzi mi o kod
od zera + Makefile.
Post by Sektor van Skijlen
Ta funkcjonalność już jest.
Wiem, że są prekompiled headers, ale jakoś ich nie widzę (poza stdafx.h).
Post by Sektor van Skijlen
Jeśli możemy zamiast pliku *.h użyć pliku
*.gch (a wzorce, jak wiadomo, definiuje się w pliku *.h), to znaczy że
nie potrzebujemy kodu źródłowego wzorca, żeby wygenerować
konkretyzację wzorca.
Muszę to oblookać.
Post by Sektor van Skijlen
Chyba że - podobnie jak pp. Lewandowski i Karpierz - uważasz, że
wzorce w C++ to taki inny makrogenerator.
Ej! Nie ubliżaj mi! :-)
Post by Sektor van Skijlen
Myślę, że wejdzie, zresztą w tej chwili to już jest tylko stwierdzenie
faktu. W gcc ta funkcjonalność istnieje od dawna i bez extern.
Jak? Mi się nie udało tego nigdy sensownie odpalić. Jak masz jakieś
swoje "blog like" doświadczenia to daj mi linka proszę.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Seweryn Habdank-Wojewódzki
2007-06-11 09:36:29 UTC
Permalink
Witam
Post by Sektor van Skijlen
Rozwijać go z czego innego? Rzeczywiście twoja wyobraźnia jest
maleńka. Już od dłuższego czasu kompilatory posiadają coś, co się
nazywa "precompiled headers".
Zrobiłem mały risercz nt. precompiled headers i jest rochę kanał
(przynajmniej pod gcc).

1. Możesz mieć tylko jeden taki header (nie wiem co to dokładanie znaczy,
ale to jest kiepskie, bo fajnie byłoby mieć możliwość prekompilować sobie
każdy używany header w programie jako precompiled. Np. wspólne headeryw w
jednym pliku, a reszta jak kto co potrzebuje.

2. prekompilowny header stoi trochę w poprzek kieyd masz kod dobrze
zaprojektowany i składa się z wielu mały bybliotek, a każda z nich woła
tylko takie headery, które potrzebuje. Wtedy taki wspólny header jest
bardzo mały wszczególności, może to być zbiór pusty - np. klasy
strumieniowe ładują <iostream> a nie ładują <vector>, zato <vector> ładują
klasy pracujące na danych ale one nie potrzebują <iostream>.

Zresztą pod tym względem polecam studium projektu boost::date_time. Tam jest
tak, że klasy główne są oddzielone od deklaracji jakichkolwiek io.
Czyli w skrócie masz tak:

my_lib_main.hpp
my_lib_io.hpp

my_lib.hpp -> zawiera tylko include my_lib_main.hpp i my_lib_io.hpp.

Jak nie potrzebujesz io to go nie wołasz, to jest bardzo dobre, bo każde io
zawsze zajmuje dużo miejsca. Czy to iostream i fstream czy inne cstdio.

Czyli troche kanał z precompiled headers, ale liczę na to, że ktoś obali
moje złe doświadczenia.
Post by Sektor van Skijlen
Myślisz, że dla jakiego języka to
powstało? Dla C, w którym parsowanie pliku nagłówkowego to myk i
gotowe?
Nie.
Post by Sektor van Skijlen
Ta funkcjonalność już jest. Jeśli możemy zamiast pliku *.h użyć pliku
*.gch (a wzorce, jak wiadomo, definiuje się w pliku *.h), to znaczy że
nie potrzebujemy kodu źródłowego wzorca, żeby wygenerować
konkretyzację wzorca.
Szkoda, że nie umiem zmusić gcc aby obsługiwało pliki hpp.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Paweł
2007-06-11 10:23:05 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
1. Możesz mieć tylko jeden taki header (nie wiem co to dokładanie znaczy,
ale to jest kiepskie,
* Only one precompiled header can be used in a particular compilation.

i znaczy to, tylko, ze gcc laduje taki binarny snapshot i potem
jak mu cos brakuje, to przetwarza pozostale naglowki normalnie.
jesli by mial ladowac kilka .gch, to musialby porownywac, to co juz
wczytal i co jeszcze moze sobie doczytac z kolejnych .gch.
jesli taki sredni .gch zajmuje po kilkanascie/kilkadziesiat MB,
to obawiam sie, ze takie babranie moze byc wolne.
oczywiscie pewnie mozna to poprawic, wiec jak chcesz miec obsluge
wielu .gch, to gcc jest opensource :)
Post by Seweryn Habdank-Wojewódzki
2. prekompilowny header stoi trochę w poprzek kieyd masz kod dobrze
zaprojektowany i składa się z wielu mały bybliotek, a każda z nich woła
tylko takie headery, które potrzebuje.
pch uzywa sie glownie do zebrania i skompilowania naglowkow
implementacji, a nie interfejsow z deklaracjami wyprzedzajacymi.
jak masz tysiace plikow implementacji i kazdy z nich uzywa np. stl-a,
to zebranie w kupie /usr/include/{stdc++.h,stdtr1c++.h,itp.},
skompilowanie i uzywanie daje widocznego kopa.
Post by Seweryn Habdank-Wojewódzki
Szkoda, że nie umiem zmusić gcc aby obsługiwało pliki hpp.
http://gcc.gnu.org/ml/gcc-patches/2007-02/msg00331.html
Seweryn Habdank-Wojewódzki
2007-06-11 10:42:09 UTC
Permalink
Witam
Post by Paweł
Post by Seweryn Habdank-Wojewódzki
1. Możesz mieć tylko jeden taki header (nie wiem co to dokładanie znaczy,
ale to jest kiepskie,
* Only one precompiled header can be used in a particular compilation.
No tak.
Post by Paweł
i znaczy to, tylko, ze gcc laduje taki binarny snapshot i potem
jak mu cos brakuje, to przetwarza pozostale naglowki normalnie.
OK.
Post by Paweł
jesli by mial ladowac kilka .gch, to musialby porownywac, to co juz
wczytal i co jeszcze moze sobie doczytac z kolejnych .gch.
Rozumiem.
Post by Paweł
jesli taki sredni .gch zajmuje po kilkanascie/kilkadziesiat MB,
to obawiam sie, ze takie babranie moze byc wolne.
Zgadza się.
Post by Paweł
oczywiscie pewnie mozna to poprawic, wiec jak chcesz miec obsluge
wielu .gch, to gcc jest opensource :)
Raczej nie widzę zalet.
Post by Paweł
Post by Seweryn Habdank-Wojewódzki
2. prekompilowny header stoi trochę w poprzek kieyd masz kod dobrze
zaprojektowany i składa się z wielu mały bybliotek, a każda z nich woła
tylko takie headery, które potrzebuje.
pch uzywa sie glownie do zebrania i skompilowania naglowkow
implementacji, a nie interfejsow z deklaracjami wyprzedzajacymi.
Czyli? Nie rozróżniam tego. Czym różni się pch od gch?
Post by Paweł
jak masz tysiace plikow implementacji i kazdy z nich uzywa np. stl-a,
to zebranie w kupie /usr/include/{stdc++.h,stdtr1c++.h,itp.},
skompilowanie i uzywanie daje widocznego kopa.
A jak to sprawdzić. Mam taki projekt, gdzie udało mi się odseparować
common.h, tam są właśnie różniaste headery w szczególności, kawałki boosta
i biblioteki standardowej i za nic w świecie (czy mam common.h.gch czy go
nie mam) nie przyspiesza kompilacji.
W szczególności liczyłem na to, że boosta mi się uda przyspieszyć, ale nic.
A może gcc po prostu nie widzi pliku gch (mam opcję -I.)? W sumie tego też
nie umiem sprawdzić.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Zbyszek Malec
2007-06-11 10:46:51 UTC
Permalink
Dnia Mon, 11 Jun 2007 12:42:09 +0200, Seweryn Habdank-Wojewódzki
Post by Seweryn Habdank-Wojewódzki
A może gcc po prostu nie widzi pliku gch (mam opcję -I.)? W sumie tego też
nie umiem sprawdzić.
możesz dać obok pliku gch plik h (tudzież hpp) który będzie miał w środku
#error - jak dostaniesz errora to znaczy że używasz zwykłego headera.
--
Zbyszek Malec Ustronie 104
jid: ***@jid.pl
Seweryn Habdank-Wojewódzki
2007-06-11 10:57:16 UTC
Permalink
Witam
Post by Zbyszek Malec
Dnia Mon, 11 Jun 2007 12:42:09 +0200, Seweryn Habdank-Wojewódzki
Post by Seweryn Habdank-Wojewódzki
A może gcc po prostu nie widzi pliku gch (mam opcję -I.)? W sumie tego
też nie umiem sprawdzić.
możesz dać obok pliku gch plik h (tudzież hpp) który będzie miał w środku
#error - jak dostaniesz errora to znaczy że używasz zwykłego headera.
Dzięki spróbuję.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Paweł
2007-06-11 11:34:27 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Paweł
Post by Seweryn Habdank-Wojewódzki
2. prekompilowny header stoi trochę w poprzek kieyd masz kod dobrze
zaprojektowany i składa się z wielu mały bybliotek, a każda z nich woła
tylko takie headery, które potrzebuje.
pch uzywa sie glownie do zebrania i skompilowania naglowkow
implementacji, a nie interfejsow z deklaracjami wyprzedzajacymi.
Czyli? Nie rozróżniam tego. Czym różni się pch od gch?
pch to skrot od precompiled headers. takie ozneczenie z tego
co widze, uzywa sie man/info i flagach kompilatora, np. -Winvalid-pch
.gch to rozszerzenie nazwy pliku (obstawiam na gnu compiled headers).
Post by Seweryn Habdank-Wojewódzki
A może gcc po prostu nie widzi pliku gch (mam opcję -I.)?
W sumie tego też nie umiem sprawdzić.
$ g++ -Wall -Winvalid-pch -O2 -c common.hpp \
-o precompiled/common.hpp.gch

$ strace -f g++ -Wall -Winvalid-pch -O2 \
-include precompiled/common.hpp main.cpp 2>&1 \
|egrep 'open.*gch'

[pid 26792] open("./precompiled/common.hpp.gch", O_RDONLY|O_NOCTTY) = 6
Rafał Maj
2007-06-10 19:41:08 UTC
Permalink
Sektor van Skijlen <***@q66g2000hsg.googlegroups.com>
Sunday, 10 June 2007 20:43
Post by Sektor van Skijlen
posiadamy jedynie pliki nagłówkowe, które mogą zawierać cokolwiek, a
następnie w plikach *.o mogą się zawierać tylko i wyłącznie definicje
obiektów POD oraz skompilowane wersje funkcji plus odwołania do innych
1. precompiled header (czasem czyni cuda np x5 szybsza kompilacja gdy pliki
są małe a za to includują całą masę skomplikowanych nagłówkół np pół boosta
i std)

lub

2. export? ale specjaliści już stwierdzili że to po prostu za trudne do
sensownej implementacji
Sebastian Kaliszewski
2007-06-13 09:22:43 UTC
Permalink
Post by Maciej Sobczak
Post by Sulsa
Post by Maciej Sobczak
To nie jest tylko kwestia rozmiaru, ale też np. tego, jak działa
konstruktor kopiujący.
I czy w ogóle jest tam jakiś dostępny konstruktor kopiujący.
Ale to wszystko da sie okreslic. Ktorys z grupowiczow podal przyklad
kompilatora borladna, ktory to wlasnie robil.
I co - robi to również wtedy, gdy definicji klasy jeszcze *nie ma*?
Nie wiem co robi kompilator Borlanda, ale zapewniam cię, że nie ma żadnego
problemu ze zrobieniem w ten sposób kompilatora. To są podstawy.
Post by Maciej Sobczak
No to niezły jest ten kompilator Borlanda - Chuck Norris wśród
kompilatorów.
ROTFL!
Post by Maciej Sobczak
Post by Sulsa
Post by Maciej Sobczak
Deklarując klasę B dajesz kompilatorowi do zrozumienia, że *jest* taka
klasa, a nie jakie są szczegóły jej implementacji. Skoro tak, to nie
posługuj się w dalszych kontekstach operacjami, które tych szczegółów
wymagają.
ale to da sie okreslic
Nie da się, bo w tym miejscu nie wiadomo jeszcze, gdzie szukać
definicji klasy.
Co to znaczy w tym miejscu. "W tym miejscu" to jest zaszłość historyczna.
Kompilatorowi może być wsio-ryba z tym miejscem.
Post by Maciej Sobczak
Post by Sulsa
To opisalem dalej, nawiazujac jescze do tego pytania to tak mozna by
odpowiedziec na kazda slabosc jezyka, bo czym programista kierowal sie
chcac napisac program w sposob latwiejszy/przyjemniejszy - odpowiedz
jest zawarta w pytaniu.
To nie jest kwestia tego, czy sposób jest łatwiejszy/przyjemniejszy.
To jest kwestia tego, czy walenie w klawiaturę było poprzedzone jakimś
etapem projektowym. Gdyby był, to nie miałbyś modułów, które mają
silne cykliczne zależności - a wtedy Twój problem w ogóle by nie
wystąpił.
Sorry, ale problem nie ma tu nic do modułów. Zależność (słabą) masz miedzy
klasami. To nie Java, tu moduł != klasa.
Post by Maciej Sobczak
Post by Sulsa
A problem ktory opisalem nie wydaje sie trudny
do rozwiazania
Oczywiście, że nie. Wystarczy zrobić sensowny układ modułów i po
problemie.
Wystarczy użyć innego języka i po problemie :)
Post by Maciej Sobczak
Język daje Ci ogromną swobodę podziału programu na moduły, które będą
mogły być kompilowane niezależnie.
Język ma akurat kompletnie spaprany system modułów.

pzdr
\SK
Seweryn Habdank-Wojewódzki
2007-06-13 09:52:03 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Post by Maciej Sobczak
Język daje Ci ogromną swobodę podziału programu na moduły, które będą
mogły być kompilowane niezależnie.
Język ma akurat kompletnie spaprany system modułów.
A coś konkretnie? Czego nie da się zrobić w C++ a można w innych językach?
Pytam poważnie, bo bardzo mnie ciekawi jakie problemy są z modułami, a z
których nie zdaję sobie sprawy.

No oczywiście poza hakami typu #define private public, którymi pewni
osobnicy rzucali (nie Ty), a potem dodawali, że im to skórę uratowało.
Rozumiem, że w spadku dostali skompilowane biblioteki, które cenną
funkcjonalność pochowały do sekcji prywatnej i trzeba było to łatać.
Ciekawe jakby to zrobili w Javie, czy C#?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sebastian Kaliszewski
2007-06-13 10:37:57 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
Post by Maciej Sobczak
Język daje Ci ogromną swobodę podziału programu na moduły, które będą
mogły być kompilowane niezależnie.
Język ma akurat kompletnie spaprany system modułów.
A coś konkretnie?
Ten system jest w postaci przyzerowej-zdegeenrowanej. Prawie go nie ma.
Post by Seweryn Habdank-Wojewódzki
Czego nie da się zrobić w C++ a można w innych językach?
Np. mieć porządne rozdzielenie interfejsu od implementacji a nie C++ mydło z
makiem. Treść szablonu to nie jest interfejs. Pola prywatne klasy takoż.
Treśc metod inline też.

Pomysł, żeby nagłówki (zwykle dziesiątki tysięcy linii) kompilować w każdej
jednostce kompilacji też jest kiepski. Na to są obejścia w rodzaju
precompiled headers, ale to są obejścia mało przenośne i niekompletne. Jak
masz kod z dużą ilością szablonów które zmieniasz to i zysk często jest
kiepski (np. nagłówki w gcc)
Post by Seweryn Habdank-Wojewódzki
Pytam poważnie, bo bardzo mnie ciekawi jakie problemy są z modułami, a z
których nie zdaję sobie sprawy.
1. jednostka kompilacji po skompilowaniu nie jest "samonośna". Sama w sobie
nic nie znaczy -- trzeba mieć tonę nagłówków.
2. jednostki kompilacji nie są nawet przyzwoicie rozdzielony. Stąd np różne
zabawne UB jak się zrobi klasę o tej samej nazwie w dwu różnych jednostkach
kompilacji. Przy porządnym systemie modułów takiego badziewia nie ma.
Post by Seweryn Habdank-Wojewódzki
No oczywiście poza hakami typu #define private public, którymi pewni
osobnicy rzucali (nie Ty), a potem dodawali, że im to skórę uratowało.
Rozumiem, że w spadku dostali skompilowane biblioteki, które cenną
funkcjonalność pochowały do sekcji prywatnej i trzeba było to łatać.
Ciekawe jakby to zrobili w Javie, czy C#?
Zdekompilowali bytekod zmienili co trzeba i zbudowali od nowa po swojemu.

pzdr
\SK
Jedrzej Dudkiewicz
2007-06-13 11:43:01 UTC
Permalink
Post by Sebastian Kaliszewski
Treść szablonu to nie jest interfejs.
A jak proponujesz przeprowadzać kompilację szablonu dla nowego typu
parametrów bez znajomości treści szablonu?

JD
Jakub Debski
2007-06-13 11:49:12 UTC
Permalink
Post by Jedrzej Dudkiewicz
A jak proponujesz przeprowadzać kompilację szablonu dla nowego typu
parametrów bez znajomości treści szablonu?
polecam przeczytać Zagadnienie 10 z "Exceptional C++ Style" (PL:
"Niezwykły styl języka C++") Suttera.

Zacytuję fragment:
"Jedyni implementatorzy słowa kluczowego export, programiści z firmy
EDG, opisują swoje doświadczenia z jego implementacją jako
najtrudniejsze w historii prac nad językiem C++". Dalej są
uzasadnienia.

pozdrawiam
Jakub
Sebastian Kaliszewski
2007-06-13 12:31:58 UTC
Permalink
Post by Jedrzej Dudkiewicz
Post by Sebastian Kaliszewski
Treść szablonu to nie jest interfejs.
A jak proponujesz przeprowadzać kompilację szablonu dla nowego typu
parametrów bez znajomości treści szablonu?
Co to jest treść szablonu? Liczy się informacja o jego budowie -- to może
być po prostu umieszczone w pliku "obiektowym" (.o lub .obj)

Jakoś, kurczę, w innych językach z generykami, typu OCaml czy Haskell to działa.

pzdr
\SK
Jedrzej Dudkiewicz
2007-06-13 12:27:53 UTC
Permalink
Post by Sebastian Kaliszewski
Co to jest treść szablonu? Liczy się informacja o jego budowie -- to może
być po prostu umieszczone w pliku "obiektowym" (.o lub .obj)
Jakoś, kurczę, w innych językach z generykami, typu OCaml czy Haskell to działa.
No więc nie wiem, jak jest zrobione, to pytam :] W szczególności chyba słabo
wygląda inlineowanie takich funkcji, szczególnie przy dużym stopniu
zagłębienia. Chociaż ponoć kompilator Intela czy MS potrafi wciągać funkcje
już skompilowane - więc chyba się da.

JD
Seweryn Habdank-Wojewódzki
2007-06-13 14:49:50 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Co to jest treść szablonu? Liczy się informacja o jego budowie -- to może
być po prostu umieszczone w pliku "obiektowym" (.o lub .obj)
Jakoś, kurczę, w innych językach z generykami, typu OCaml czy Haskell to działa.
Była już dyskusja o generykach w Haskelu. One są małe przy tym co w C++,
więc nie ma co porównywać, tam generyk to jest po prostu wskaźnik na
interfejs klasy tyle i nic więcej, koniec kropka. A że jezyk jest funkcyjny
to może nie potrzebuje więcej, tego nie potrafię ocenić.

Zresztą to nie jest ani dobre ani złe, Heskel leje na to czym jest klasa.
Już nie mówię o conceptach, czy nawet traitsach.

W Javie generyki są właśnie na Haskelu wzorowane i co mogą? Nie za wiele.
Zobacz sobie na Integer i Double w Javie, z czego one się wywodzą i zastanów
się jak zapytasz:

is_integral<T>?

To samo jest w Haskelu, jak klasa sama nie odpowie na to pytanie, to z
zewnątrz nie podasz odpowiedzi za nią, co się wiąże z tym, że
ustalając "traitsy" dla klasy zawsze musisz grzebać w jej wnętrzu -
dziękuję bardzo.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Seweryn Habdank-Wojewódzki
2007-06-13 15:11:26 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Czego nie da się zrobić w C++ a można w innych językach?
Np. mieć porządne rozdzielenie interfejsu od implementacji a nie C++ mydło
z makiem. Treść szablonu to nie jest interfejs.
Z szablonami nie potrafię dyskutować, bo coś jest uzyskiwane w prekompiled
headera, a coś nie, więc nie wiem jak daleko można je separować od headera.
Post by Sebastian Kaliszewski
Pola prywatne klasy takoż.
To jest śmieszne. Bo albo robisz pimpla jak się boisz o prywatne pola. Albo
nie.
W Javie nic nie zrobisz. Masz klasę i pola. Jak skompilujesz to nie masz
headera i musisz się posiłkować JavaDoc (nie liczę na ich idealność),
jak nie skompilujesz masz wszystko na tacy - można to łatać pimplem, również
kompilując pimpla a interfejs klasy dając w postaci kodu.
Nie wiem jak to jest w Pythonie. Jak zrobić, aby interfejs był dostępny, a
kod aby chować.
Post by Sebastian Kaliszewski
Treść metod inline też.
Rozumiem. Tak tu masz rację przydałoby się móc wyrzucić inline poza header.
Post by Sebastian Kaliszewski
Pomysł, żeby nagłówki (zwykle dziesiątki tysięcy linii) kompilować w
każdej jednostce kompilacji też jest kiepski. Na to są obejścia w rodzaju
precompiled headers, ale to są obejścia mało przenośne i niekompletne. Jak
masz kod z dużą ilością szablonów które zmieniasz to i zysk często jest
kiepski (np. nagłówki w gcc)
Czasem jednak dają. Mi czas kompilacji projektu spadł o 50%.
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Pytam poważnie, bo bardzo mnie ciekawi jakie problemy są z modułami, a z
których nie zdaję sobie sprawy.
1. jednostka kompilacji po skompilowaniu nie jest "samonośna". Sama w
sobie nic nie znaczy -- trzeba mieć tonę nagłówków.
Tak. Ale one są informacyjne, to nie sa pliki bezsensu.
Post by Sebastian Kaliszewski
2. jednostki kompilacji nie są nawet przyzwoicie rozdzielony. Stąd np
różne zabawne UB jak się zrobi klasę o tej samej nazwie w dwu różnych
jednostkach kompilacji. Przy porządnym systemie modułów takiego badziewia
nie ma.
E tam. Jak się używa przestrzeni nazw to takich jaj nie ma. Mam w prawie
każdym cpp w którym istnieje "interfejs prywatny" nienazwaną przestrzeń i
takie chece się nie zdarzają. Mój własnej konstrukcji wizrd do plików cpp
odrazu zachęca mnie do tego żeby pakować wszystko do namespace { } tak więc
jak coś zapomnę "upublicznić" to kompilator mi krzyczy.

Poza tym w ogóle jest jakoś tak, że c++ programiści z bożej łaski nie
stosują przestrzeni nazw tak jak to się powinno robić ? np. jak to jest
przyjęte w pakietowaniu w Pythonie, czy innej Javie.
A już do szczytów należy robienie własnej przestrzeni std, ot tak po prostu,
aby nie musieć samemu pisać std::.
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
No oczywiście poza hakami typu #define private public, którymi pewni
osobnicy rzucali (nie Ty), a potem dodawali, że im to skórę uratowało.
Rozumiem, że w spadku dostali skompilowane biblioteki, które cenną
funkcjonalność pochowały do sekcji prywatnej i trzeba było to łatać.
Ciekawe jakby to zrobili w Javie, czy C#?
Zdekompilowali bytekod zmienili co trzeba i zbudowali od nowa po swojemu.
Oczywiście! Już widzę jak się palą do takiego zadania. Prędzej przepiszą od
zera, pozwą do sądu pisarza, cokolwiek tylko nie dekompilacja.
Wystarczy, że kod był cokolwiek zabadziewiony i liczył cokolwiek więcej niż
10000 lini, a jeszcze jak zawierał dziwną strukturę w całości to nikt Ci
tego nie będzie rozdłubywał.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sebastian Kaliszewski
2007-06-13 08:37:45 UTC
Permalink
Post by Sulsa
Wknocu ZOSTALEM ZMUSZONY przez
kompilator do wybrania ulozenia klas w plikach takiego jak nie
chcialem,
Nie zostałeś. Na to wystarcza wciągnięcie definicji metod poza (poniżej)
definicję klasy. Nadal możesz miec w jednym pliku.

pzdr

\SK
Jakub Debski
2007-06-08 07:31:55 UTC
Permalink
Post by Sulsa
wiem ze nie wie i wlasnie o to sie caly czas pytam: dlaczego w 21 wieku
kompilator nie moze sobie zrobic dwoch przebiegow rzeby ten rozmiar
okreslic(jest to mozliwe poza przypadkiem, ktory podalem w pierwszym
poscie) . Czym szanowny komitet kierowal sie pozostawiajac taki
archaizm w jezyku, rozumiem ze w latach siedemdziesiatych moglo to
niepotrzebnie wydluzac kapilacje, ale teraz nikt by tego nie zauwazyl,
a wygoda programowania jest duzo wazniejsza aby jezyk przetrwal.
Pewnie się projektanci języka i kompilatorów kierują tym, że nie jest
to nikomu potrzebne... A jak komuś potrzebne jest, to znaczy, że trzeba
go nauczyć dlaczego potrzebne mu to nie jest :)

pozdrawiam
Jakub
Seweryn Habdank-Wojewódzki
2007-06-08 16:42:32 UTC
Permalink
Witam
Post by Jakub Debski
Pewnie się projektanci języka i kompilatorów kierują tym, że nie jest
to nikomu potrzebne... A jak komuś potrzebne jest, to znaczy, że trzeba
go nauczyć dlaczego potrzebne mu to nie jest :)
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?

Sam zapis class B; pozwala na to, że gdzieś indziej masz to określone. To
wcale nie oznacza, że to jest określone w tym samym pliku poniżej.

W sumie nie znam się dokładnie na szczegółach kompilacji, ale odnoszę
wrażenie, że to jest nie proste jak przychodzi mieć na uwadze tak wiele
plików i różne skomplikowanie połączeń pomiędzy nimi, oraz to, że jak masz
skompilowany plik cpp, i nic w jego rejonie nie zmieniasz to kolejna
kompilacja go nie rusza. Wyobraźmy sobie, że dopuszczamy wieloprzebieg na
wielu plikach, jeśli ktoś zmieni cokolwiek w w pliku 124, trzeba pamiętać,
że on był związany z plikiem 22, więc każda kompilacja wieloprzebiegowa i
wieloplikowa, staje się kompilacją kompletną?

Może ktoś moje wątpliwości rozwieje?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Jakub Debski
2007-06-08 17:23:34 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?
[...]
Może ktoś moje wątpliwości rozwieje?
Próbując przeanalizować wieloprzebieg od strony kompilacji i
potencjalne problemy w momencie, gdy pojawiłoby się kilka definicji tej
samej klasy, natrafiłem na taką ciekawą rzecz:

///////////////// plik pierwszy

#include <stdio.h>

class A {
public:
A() { printf("pierwszy\n"); };
};

A global;

///////////////// plik drugi

#include <stdio.h>

class A {
public:
A() { printf("drugi\n"); };
void test() { printf("test drugi"); };
};

int main(void)
{
A a;
a.test();
return 0;
}

Wynik:
pierwszy
pierwszy
test drugi

mam pod ręką tylko Visual Studio 2003, więc nie wiem czy ten sam efekt
będzie pod innymi kompilatorami.

po usunięciu "A global;" wynikiem jest:
drugi
test drugi

Są też inne ciekawostki przy dodawaniu wspólnych składowych i odwołań
do nich w poszczególnych plikach.

(właśnie wyjeżdżam na weekend, więc przeczytam i odpowiem dopiero po
weekendzie)

pozdrawiam
Jakub
Maciej Sobczak
2007-06-08 21:06:39 UTC
Permalink
Post by Jakub Debski
Próbując przeanalizować wieloprzebieg od strony kompilacji i
potencjalne problemy w momencie, gdy pojawiłoby się kilka definicji tej
Ta ciekawa rzecz to UB (3.2/5, zwłaszcza ostatnie zdanie).

--
Maciej Sobczak
http://www.msobczak.com/
Jakub Debski
2007-06-11 07:28:07 UTC
Permalink
Post by Maciej Sobczak
Ta ciekawa rzecz to UB (3.2/5, zwłaszcza ostatnie zdanie).
dzięki.

pozdrawiam
Jakub
Sektor van Skijlen
2007-06-10 19:02:12 UTC
Permalink
Post by Jakub Debski
Post by Seweryn Habdank-Wojewódzki
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?
[...]
Może ktoś moje wątpliwości rozwieje?
Próbując przeanalizować wieloprzebieg od strony kompilacji i
potencjalne problemy w momencie, gdy pojawiłoby się kilka definicji tej
///////////////// plik pierwszy
#include <stdio.h>
class A {
A() { printf("pierwszy\n"); };
};
A global;
///////////////// plik drugi
#include <stdio.h>
class A {
A() { printf("drugi\n"); };
void test() { printf("test drugi"); };
};
int main(void)
{
A a;
a.test();
return 0;
}
pierwszy
pierwszy
test drugi
mam pod ręką tylko Visual Studio 2003, więc nie wiem czy ten sam efekt
będzie pod innymi kompilatorami.
drugi
test drugi
Są też inne ciekawostki przy dodawaniu wspólnych składowych i odwołań
do nich w poszczególnych plikach.
(właśnie wyjeżdżam na weekend, więc przeczytam i odpowiem dopiero po
weekendzie)
Oficjalnie to jest UB. Natomiast w przypadku gcc polega to na tym, że
nastąpiło tu słabe wiązanie z uwagi na funkcję inline (funkcja
zdefiniowana w ciele klasy podlega tym samym prawom, co funkcja
inline). Konkretnie chodzi o konstruktor klasy A.

Efekt, który tu wystąpił, wynika stąd, że zostały dostarczona dwie
oddzielne definicje funkcji inline, a ponieważ funkcje inline
podlegają słabemu wiązaniu, więc pierwsza znaleziona definicja jest
uważana za obowiązującą (gdyby podlegały silnemu wiązaniu, to
znalezienie drugiej definicji spowodowałoby błąd). Oczywiście to
zachowanie jak najbardziej mieści się w UB, więc tak czy siak
poleganie na tym, że takie będzie zachowanie, jest zakazane.

Natomiast nie pokazałeś jeszcze wszystkiego, co taka definicja
potrafi. Otóż, mógłbyś np. mieć dwie osobne definicje klas z różnymi
zestawami pól. Zatem metody zdefiniowane razem w pliku z taką klasą
operowałyby zestawami pól takimi, jakie znalazły się w definicji klasy
w tym pliku. W efekcie, każda mogłaby myśleć, że operuje obiektem
klasy A (i kompilator w związku z tym nie zauważy nieprawidłowości), a
tak naprawdę operuje zupełnie innymi obiektami i reinterpretuje je po
swojemu.

Fakt, że kompilatory mogłyby jednak coś z tym zrobić. Np. generować
odpowiednią sygnaturę do klasy i przywiązywać metody nie do klasy o
danej nazwie, lecz klasy o danej sygnaturze. Wtedy np. jeśli zmienimy
definicję klasy, to zmieni się jej sygnatura. Kompilator umiałby wtedy
zatem stwierdzić zarówno, że funkcja realizująca metodę została
skompilowana dla klasy X, ale o innej sygnaturze, jak również (ale to
już raczej linker) wykryć istnienie w zestawie kompilacji wielu klas o
tej samej nazwie i innej sygnaturze. Sygnatura oczywiście powinna się
wygenerować taka sama, jeśli definicje klasy są takie same. Zmianę
sygnatury mogłyby spowodować:
- dodanie lub usunięcie pól lub klas dziedziczonych
- zmiana kolejności pól lub klas dziedziczonych
- zmiana klasy niepolimorficznej na polimorficzną lub odwrotnie (lub
jakakolwiek podobna zmiana w klasie dziedziczonej)

Inaczej mówiąc zatem, sygnatura powinna być wygenerowana na podstawie
pól i sygnatur klas dziedziczonych.

Oczywiście taki ficzer musiałby mieć już specjalne wsparcie w
linkerze. Jak na razie jedyne wsparcie w linkerze do C++ (przynajmniej
jeśli chodzi o GNU ld) to silne wiązanie.
Jakub Debski
2007-06-11 08:17:30 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?
Możliwość istnienia wieloprzebiegu całkowicie zmieniałaby istniejące
implementacje języka oraz sam standard. Po przemyśleniu widzę, jak
wiele problemów wieloprzebieg by powodował.

Przede wszystkim zwalniałby programistów z konieczności używania plików
nagłówkowych, co prowadziłoby jedynie do sztucznego podziału na
interfejs i implementację. Klasy bez problemu można by definiować w
plikach cpp, co już samo w sobie jest złe, a czemu kompilator by nie
przeciwdziałał. Według mnie już teraz w C++ podział na interfejs i
implementację jest zbyt słaby.
Ponieważ kompletność typu klasy nie byłaby wymagana w momencie
operowania na danej jednostce translacji, kompilator musiałby sprawdzać
wiele tablic symboli. W C++ wystarczająco skomplikowana jest praca z
jedną tablicą symboli. Efektem tego i tak trudne w implementacji ADL
stałoby się koszmarem.
Wydaje mi się, że kompilator jednocześnie musiałby kompilować wiele
plików. Przykładowo zaczynałby kompilować plik pierwszy, ktory
wykorzystuje typ zdefiniowany w pliku drugim. Musiałby częściowo
skompilować plik pierwszy, następnie drugi (który znowu może zależeć od
innych), po skompilowaniu drugiego wrócić do pierwszego itd. A co
jeżeli plik drugi wykorzystuje inny typ zdefiniowany w pliku pierwszym?
Koszmar.
Idąc dalej - kompilacja wymagałaby przechowywania informacji o
wszystkich jednostkach translacji, w których następowała definicja lub
deklaracja typu. Jeżeli w każdym pliku projektu byłaby definicja
jakiegoś typu, podczas kompilacji konieczne byłoby przechowywanie
całego projektu w pamięci.
Komunikaty błędów kompilacji byłyby znacznie mniej czytelne dla
użytkownika.
Istniałaby możliwość cykli - definicja klasy A wymaga B, B wymaga C,
zaś C wymaga A. Znalezienie takich cykli przez kompilator byłoby bardzo
kłopotliwe.
W przypadku braku plików nagłówkowych i przy możliwości definicji klasy
w pliku implementacji kompilacja tylko nowych elementów byłaby
niezmiernie trudna. Aktualnie kompilator musi przebudować tylko te
pliki, które zostały zmodyfikowane lub które włączają pliki nagłówkowe,
które zostały zmodyfikowane. W rozpatrywanym przypadku kompilator
musiałby przechowywać informacje o relacjach między typami i sprawdzać,
czy typ został zmodyfikowany, a wtedy przebudować wszelkie pliki, w
których następuje wykorzystanie tego typu, lub typów zależnych od tego
typu.
Występowałaby większość problemów, ze względu na które słowo kluczowe
export nie zostało jeszcze poprawnie zaimplementowane.

pozdrawiam
Jakub
Sebastian Kaliszewski
2007-06-13 09:47:52 UTC
Permalink
Post by Jakub Debski
Post by Seweryn Habdank-Wojewódzki
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?
Możliwość istnienia wieloprzebiegu całkowicie zmieniałaby istniejące
implementacje języka oraz sam standard. Po przemyśleniu widzę, jak wiele
problemów wieloprzebieg by powodował.
Przede wszystkim zwalniałby programistów z konieczności używania plików
nagłówkowych,
Wcale nie. Wieloprzebieg nie wpływa na podział na moduły.
Post by Jakub Debski
co prowadziłoby jedynie do sztucznego podziału na
interfejs i implementację. Klasy bez problemu można by definiować w
plikach cpp, co już samo w sobie jest złe,
Absolutnie nie jest złe, jesli klasa jest lokalna dla jednosktki kompilacji.
Post by Jakub Debski
a czemu kompilator by nie
przeciwdziałał.
Teraz też nie przeciwdziała.
Post by Jakub Debski
Według mnie już teraz w C++ podział na interfejs i
implementację jest zbyt słaby.
Jest kompletnie schrzaniony i tyle. Wynika to wprost z tego że schrzaniona
jest modularyzacja/pakietyzacja. Z wieloprzebiegową kompilacją nie ma nic
wspólnego.
Post by Jakub Debski
Ponieważ kompletność typu klasy nie byłaby wymagana w momencie
operowania na danej jednostce translacji,
Nic takiego z wieloprzebiegowości nie wynika.

[...]
Post by Jakub Debski
Wydaje mi się, że kompilator jednocześnie musiałby kompilować wiele
plików.
Absolutnie nie.

[...]
Post by Jakub Debski
Istniałaby możliwość cykli - definicja klasy A wymaga B, B wymaga C, zaś
C wymaga A. Znalezienie takich cykli przez kompilator byłoby bardzo
kłopotliwe.
Kompilator nie ma ui nie miałby z tym problemu.

[...]
Wnioski wysunięte z fałszywych założeń nie wnoszą nic nowego

pzdr
\SK
Jakub Debski
2007-06-13 11:43:31 UTC
Permalink
Post by Sebastian Kaliszewski
Kompilator nie ma ui nie miałby z tym problemu.
[...]
Wnioski wysunięte z fałszywych założeń nie wnoszą nic nowego
Dlaczego założenia fałszywe? Z tego co napisałeś wynika, że
rozpatrujesz organizację kodu taką jak w Javie, gdzie klasa jest
związana z jednostką translacji. Ja rozpatrywałem przypadek ogólny,
czyli metody mogą być definiowane w innej jednostce.

pozdrawiam
Jakub
Sebastian Kaliszewski
2007-06-13 12:29:30 UTC
Permalink
Post by Sebastian Kaliszewski
Kompilator nie ma ui nie miałby z tym problemu.
[...]
Wnioski wysunięte z fałszywych założeń nie wnoszą nic nowego
Dlaczego założenia fałszywe? Z tego co napisałeś wynika, że rozpatrujesz
organizację kodu taką jak w Javie, gdzie klasa jest związana z jednostką
translacji.
Absolutnie nie.
Ja rozpatrywałem przypadek ogólny, czyli metody mogą być
definiowane w innej jednostce.
Ale co to ma do wieloprzebiegowości?

pzdr
\SK
Sebastian Kaliszewski
2007-06-13 09:34:22 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Jakub Debski
Pewnie się projektanci języka i kompilatorów kierują tym, że nie jest
to nikomu potrzebne... A jak komuś potrzebne jest, to znaczy, że trzeba
go nauczyć dlaczego potrzebne mu to nie jest :)
Wydaje mi się, że kłopot jest bardziej złożony. Jak zrobić wieleprzebieg,
kiedy projekt składa się z wielu np. 1000 plików?
Najnormalniej w świecie. Wieloprzebieg (wystarcza dwuprzebieg) dotyczy
kompilacji nie linkowania.
Post by Seweryn Habdank-Wojewódzki
Sam zapis class B; pozwala na to, że gdzieś indziej masz to określone. To
wcale nie oznacza, że to jest określone w tym samym pliku poniżej.
No i? Jesteś zbyt przyzyczajony do różnych specyficznych rozwiązań z C++.

Cała potrzebna informacja jest dostępna w ogóle bez pisania tego class B; To
jest zaszłość z lat 70. i wcześniejszych, gdy komputery miały mało pamięci i
kompilację robiło się z dysku na dysk.
Post by Seweryn Habdank-Wojewódzki
W sumie nie znam się dokładnie na szczegółach kompilacji, ale odnoszę
wrażenie, że to jest nie proste
To jest opanowane od dawien dawna.
Post by Seweryn Habdank-Wojewódzki
jak przychodzi mieć na uwadze tak wiele
plików i różne skomplikowanie połączeń pomiędzy nimi, oraz to, że jak masz
skompilowany plik cpp, i nic w jego rejonie nie zmieniasz to kolejna
kompilacja go nie rusza.
To jest system modułów/paketów -- zrasztą w C++ spaprany (lub lepiej
powiedzieć w stanie zdegenerowanym).
Post by Seweryn Habdank-Wojewódzki
Wyobraźmy sobie, że dopuszczamy wieloprzebieg na
wielu plikach, jeśli ktoś zmieni cokolwiek w w pliku 124, trzeba pamiętać,
że on był związany z plikiem 22, więc każda kompilacja wieloprzebiegowa i
wieloplikowa, staje się kompilacją kompletną?
Nic takiego nie występuje.
Post by Seweryn Habdank-Wojewódzki
Może ktoś moje wątpliwości rozwieje?
Rozwiewam je. System pakietów nie plącze się specjelnie z kompilacją
wieloprzebiegową.

pzdr
\SK
Seweryn Habdank-Wojewódzki
2007-06-13 10:14:40 UTC
Permalink
Witam
Post by Sebastian Kaliszewski
Najnormalniej w świecie. Wieloprzebieg (wystarcza dwuprzebieg) dotyczy
kompilacji nie linkowania.
No i? Jesteś zbyt przyzyczajony do różnych specyficznych rozwiązań z C++.
Cała potrzebna informacja jest dostępna w ogóle bez pisania tego class B;
To jest zaszłość z lat 70. i wcześniejszych, gdy komputery miały mało
pamięci i kompilację robiło się z dysku na dysk.
EEE. Chyba nie do końca. Bawię się małym projekcikiem i jak zrobiłem sobie
precompiled header z kilku (!) headerów to mi się zrobiło 33MB plik.
Nie mam aktualnie dostępu swobodnego (aby grzebać) przy dużych projektach,
ale jakbym zapodał tam robienie precompiled headera, to pewnie byłoby tego
dużo więcej, bo prekompiled mam tylko z tego co jest wspólne, a nie z
całości.
Post by Sebastian Kaliszewski
To jest system modułów/paketów -- zrasztą w C++ spaprany (lub lepiej
powiedzieć w stanie zdegenerowanym).
Może. Ciekawy jestem co można zrobić gdzieś indziej, czego tu się nie da.
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Może ktoś moje wątpliwości rozwieje?
Rozwiewam je. System pakietów nie plącze się specjelnie z kompilacją
wieloprzebiegową.
Czyli? Jak puścisz wieloprzebieg, to ograniczasz go do jednego headera, czy
pozwalasz na rekurencyjne wieloprzebieganie wszystkich includowanych
plików?

Jak zapuścisz coverage test w gcc, to cały katalog zostaje zasypany
informacjami pochodzącymi z headerów rekurencyjnie wołanych, jest tego cała
masa, czy to to chcesz przebiegać dwa razy?

Mam wrażenie to jest trochę "mowa trawa", bo języki "lepsze" po prostu nie
mają przekazywania przez kopię, czyli tam możesz sobie pisać cokolwiek i
tak przekazujesz referencję czy też wskaźnik a on zawsze ma ustalony
rozmiar. Zobacz co robisz w Javie jak przekazać chcesz kopię dajesz
clone(), a co to robi jak nie głębokie kopiowanie. Zapis tylko przykrywa
fakt, że nie ma tam żadnego obiektu są tylko refy. W Pythonie też jest
podobnie, chociaż tam (przez to, że sam Python jest pisany w C) są używane
po prostu wskaźniki i tyle. Krótko mówiąc problem jest ukrócony u samej
podstawy. Ale nikt w C++ nie zabrania używać ref czy wskaźnika. To trochę
ja w shellu aby miec zmienną pisze np. $1, czy %1, czy cokolwiek w C++
preferowany jest zapis "zmienna &" z różnymi wariantami dla CV.

Czy możesz napisać w punktach czego nie da się zrobić w C++, bo system
pakietów jest do bani?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sebastian Kaliszewski
2007-06-13 12:03:43 UTC
Permalink
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
Najnormalniej w świecie. Wieloprzebieg (wystarcza dwuprzebieg) dotyczy
kompilacji nie linkowania.
No i? Jesteś zbyt przyzyczajony do różnych specyficznych rozwiązań z C++.
Cała potrzebna informacja jest dostępna w ogóle bez pisania tego class B;
To jest zaszłość z lat 70. i wcześniejszych, gdy komputery miały mało
pamięci i kompilację robiło się z dysku na dysk.
EEE. Chyba nie do końca.
Do końca.
Post by Seweryn Habdank-Wojewódzki
Bawię się małym projekcikiem i jak zrobiłem sobie
precompiled header z kilku (!) headerów to mi się zrobiło 33MB plik.
A co ma precompiled header do wieloprzebiegowości?
To jest proteza na rozpieprzoną modułowość. I to dosyć kiespka proteza. Z
wieloprzebiegowością to nie ma nic wspólnego.
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
To jest system modułów/paketów -- zrasztą w C++ spaprany (lub lepiej
powiedzieć w stanie zdegenerowanym).
Może. Ciekawy jestem co można zrobić gdzieś indziej, czego tu się nie da.
Już napisałem w innym poscie. Języki w których jest statyczny generyzm jest
istnieją i tylko w C++ jest taka kaszana jaka jest.
Post by Seweryn Habdank-Wojewódzki
Post by Sebastian Kaliszewski
Post by Seweryn Habdank-Wojewódzki
Może ktoś moje wątpliwości rozwieje?
Rozwiewam je. System pakietów nie plącze się specjelnie z kompilacją
wieloprzebiegową.
Czyli? Jak puścisz wieloprzebieg, to ograniczasz go do jednego headera, czy
pozwalasz na rekurencyjne wieloprzebieganie wszystkich includowanych
plików?
Wszystko cały czas kompletnie mieszasz. Wieloprzebieg dotyczy *jednostki
kompilacji*. W dodatku w praktycznych kompilatorach C++ *wieloprzebieg jest*.
Post by Seweryn Habdank-Wojewódzki
Jak zapuścisz coverage test w gcc, to cały katalog zostaje zasypany
informacjami pochodzącymi z headerów rekurencyjnie wołanych, jest tego cała
masa, czy to to chcesz przebiegać dwa razy?
To *jest* przebiegane wiele, wiele razy! Za drugim razem nikt normalny nie
przebiega plików źródłowych tylko strukturę w pamięci.
Post by Seweryn Habdank-Wojewódzki
Mam wrażenie to jest trochę "mowa trawa", bo języki "lepsze" po prostu nie
mają przekazywania przez kopię
Nie prawda. Obejct pascal ma, ale też builduje się "nieco" szybciej.
Post by Seweryn Habdank-Wojewódzki
, czyli tam możesz sobie pisać cokolwiek i
tak przekazujesz referencję czy też wskaźnik a on zawsze ma ustalony
rozmiar.
To nie ma znaczenia.
Post by Seweryn Habdank-Wojewódzki
Czy możesz napisać w punktach czego nie da się zrobić w C++, bo system
pakietów jest do bani?
Pisałem.

Rozdzielenie interfejsu od implementacji jest fikcją.
Między jednostkami kompilacji są ukryte zależności które są przyczyną
"zabawnych" UB.
Kompilacja jest tragicznie powolna.
Itd.

pzdr
\SK
Jakub Debski
2007-06-13 12:04:30 UTC
Permalink
Post by Sebastian Kaliszewski
Wszystko cały czas kompletnie mieszasz. Wieloprzebieg dotyczy *jednostki
kompilacji*. W dodatku w praktycznych kompilatorach C++ *wieloprzebieg jest*.
skoro wieloprzebieg ma dotyczyć tylko jednostki kompilacji, to w jaki
sposób Twoim zdaniem (inny niż ukryty wskaźnik) kompilator ma znać
wielkość używanego obiektu?
Między innymi od tego zaczęła się dyskusja...

pozdrawiam
Jakub
Jedrzej Dudkiewicz
2007-06-13 12:34:05 UTC
Permalink
Post by Jakub Debski
Post by Sebastian Kaliszewski
Wszystko cały czas kompletnie mieszasz. Wieloprzebieg dotyczy *jednostki
kompilacji*. W dodatku w praktycznych kompilatorach C++ *wieloprzebieg jest*.
skoro wieloprzebieg ma dotyczyć tylko jednostki kompilacji, to w jaki
sposób Twoim zdaniem (inny niż ukryty wskaźnik) kompilator ma znać
wielkość używanego obiektu?
Między innymi od tego zaczęła się dyskusja...
Jeżeli działa wewnątrz klasy, co Sebastian napisał/pokazał parę postów w
tył, to może działać w obrębie jednostki kompilacji.

JD
Sebastian Kaliszewski
2007-06-13 12:46:16 UTC
Permalink
Post by Jakub Debski
Post by Sebastian Kaliszewski
Wszystko cały czas kompletnie mieszasz. Wieloprzebieg dotyczy
*jednostki kompilacji*. W dodatku w praktycznych kompilatorach C++
*wieloprzebieg jest*.
skoro wieloprzebieg ma dotyczyć tylko jednostki kompilacji, to w jaki
sposób Twoim zdaniem (inny niż ukryty wskaźnik) kompilator ma znać
wielkość używanego obiektu?
Z jego definicji?

Mowa od początku była o tej samej jednostce kompilacji. Na tym polegał
problem, że kompilator "udawał", że nie wie nic o obiekcie z tej samej
jednostki kompilacji.

pzdr
\SK
Jakub Debski
2007-06-13 13:19:58 UTC
Permalink
Post by Sebastian Kaliszewski
Mowa od początku była o tej samej jednostce kompilacji. Na tym polegał
problem, że kompilator "udawał", że nie wie nic o obiekcie z tej samej
jednostki kompilacji.
To jest oczywiste, że w ramach tej samej jednostki mógłby definicję
znaleźć.

Powyżej rozpatrywałem problem, który przedstawił Seweryn, mianowicie
"Sam zapis class B; pozwala na to, że gdzieś indziej masz to określone.
To wcale nie oznacza, że to jest określone w tym samym pliku poniżej."

pozdrawiam
Jakub
Sebastian Kaliszewski
2007-06-13 13:49:41 UTC
Permalink
Post by Jakub Debski
Post by Sebastian Kaliszewski
Mowa od początku była o tej samej jednostce kompilacji. Na tym polegał
problem, że kompilator "udawał", że nie wie nic o obiekcie z tej samej
jednostki kompilacji.
To jest oczywiste, że w ramach tej samej jednostki mógłby definicję
znaleźć.
Powyżej rozpatrywałem problem, który przedstawił Seweryn, mianowicie
"Sam zapis class B; pozwala na to, że gdzieś indziej masz to określone.
To wcale nie oznacza, że to jest określone w tym samym pliku poniżej."
Sam zapis class B; byłby w ogóle zbędny dla klas z tej samej jednostki
kompilacji.

Dla klas z zewnątrz trzeba zaś mieć mechanizm modularyzacji/pakietyzacji --
co w C++ też kuleje.

pzdr
\SK
Jedrzej Dudkiewicz
2007-06-13 15:18:06 UTC
Permalink
Post by Sebastian Kaliszewski
Dla klas z zewnątrz trzeba zaś mieć mechanizm
modularyzacji/pakietyzacji --
Post by Sebastian Kaliszewski
co w C++ też kuleje.
Mam pytanie (na poważnie, bo się nie znam): jaka jest różnica między
headerami a pakietami, oprócz tej oczywistej, że pakietów nie trzeba
kompilować, bo są w postaci daleko strawniejszej dla kompilatora?

JD
Maciej Sobczak
2007-06-13 21:51:25 UTC
Permalink
On 13 Cze, 17:18, "Jedrzej Dudkiewicz"
Post by Jedrzej Dudkiewicz
Mam pytanie (na poważnie, bo się nie znam): jaka jest różnica między
headerami a pakietami, oprócz tej oczywistej, że pakietów nie trzeba
kompilować, bo są w postaci daleko strawniejszej dla kompilatora?
Niby dlaczego mają być w strawniejszej postaci?

Najważniejszy zysk z dobrego wsparcia dla pakietów to odizolowanie
użytkownika od szczegółów implementacyjnych używanego pakietu.

W modelu z #include użytkownik dostaje nie tylko zawartość headera,
ale dodatkowo wszystkich headerów wciąganych przez ten header (i tak
rekurencyjnie aż do skrajnego przypadku, gdy jeden biedny Hello World
wciąga 50 tysięcy (!) linii kodu). Te dodatkowe "nieproszone"
definicje brudzą przestrzeń nazw.
To jest chyba najważniejsze, co można poprawić porządnymi pakietami -
bo dzięki konwersjom i makrom może wpływać na *działanie programu*.
Reszta to pierdoły.

--
Maciej Sobczak
http://www.msobczak.com/
Zbyszek Malec
2007-06-13 22:22:34 UTC
Permalink
Post by Maciej Sobczak
Reszta to pierdoły.
Ale za to wygodne pierdoły.
--
Zbyszek Malec Ustronie 104
jid: ***@jid.pl
Krzysztof Magosa 'hexio'
2007-06-11 08:23:23 UTC
Permalink
Post by Sulsa
wiem ze nie wie i wlasnie o to sie caly czas pytam: dlaczego w 21 wieku
kompilator nie moze sobie zrobic dwoch przebiegow rzeby ten rozmiar
^^^^^

Polecam zacząć od języka polskiego, a potem dopiero zająć się C++. :)
--
Krzysztof Magosa 'hexio' | hexio (at) xnet (dot) org (dot) pl
SysAdmin of xnet.org.pl | http://hexio.xnet.org.pl/
Rafał Maj
2007-06-08 18:42:43 UTC
Permalink
Post by Jakub Debski
nie chodzi o kolejność, ale o informacje na temat rozmiaru obiektu. Bez
tego nie mógłbyś przydzielić pamięci dla obiektu.
Mieszacie koledze - po prostu nie da się aby obiekt A miał w sobie obiekt B
i zarazem vice-versa, to błąd logiczny (nie tylko w C++ czy programowaniu
tylko ogólnie)
Rafał Maj
2007-06-08 18:41:47 UTC
Permalink
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
Tak jak już wszyscy napisali, chcesz niemożliwego.

Chcesz mieć pudełku do którego wkładasz drugie pudełko które zawiera w sobie
to pierwsze pudełko - to jest niewykonalne.
Marcin 'Qrczak' Kowalczyk
2007-06-08 19:32:08 UTC
Permalink
Post by Rafał Maj
Chcesz mieć pudełku do którego wkładasz drugie pudełko które zawiera w sobie
to pierwsze pudełko - to jest niewykonalne.
Nie *to* pierwsze pudełko, tylko *takie samo* pudełko jak pierwsze,
które zawiera znowu takie samo jak drugie itd.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Sulsa
2007-06-09 01:22:21 UTC
Permalink
On Fri, 08 Jun 2007 20:41:47 +0200
Post by Rafał Maj
Post by Sulsa
P.S tu rodzi sie nowe pytanie, dlaczego w naszych czasach istnieje w
jezyku cos takiego jak wymog odpowiedniego zdefiniowania kolejnosci
Tak jak już wszyscy napisali, chcesz niemożliwego.
Chcesz mieć pudełku do którego wkładasz drugie pudełko które zawiera
w sobie to pierwsze pudełko - to jest niewykonalne.
Przecież pisalm juz kilka razy, ze przyklad byl zly!!! Zanim wlaczysz
sie do dyskusji to najpier przeczytaj co ludzie wczesniej napisali.
Sektor van Skijlen
2007-06-10 19:28:11 UTC
Permalink
Post by Sulsa
Przecież pisalm juz kilka razy, ze przyklad byl zly!!! Zanim wlaczysz
sie do dyskusji to najpier przeczytaj co ludzie wczesniej napisali.
To zrób z łaski swojej przykład *dobry*, albo przestań zawracać nam
głowę. Jak na razie nie potrafisz przedstawić problemu w sposób
przekonujący, że rzeczywiście jest to problem, za to z lubością
wieszasz psy na ludziach z komitetu standaryzacyjnego, którym do pięt
nie dorastasz.
Seweryn Habdank-Wojewódzki
2007-06-04 15:40:59 UTC
Permalink
Witam
Post by Sulsa
class B;
class A{
B b;
};
class B{
A a;
};
prompt > g++ a.cpp
a.cpp:4: error: field 'b' has incomplete type
no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
A jakie jest merytoryczne uzasadnienie takiego konceptu?

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Sulsa
2007-06-05 00:25:33 UTC
Permalink
On Mon, 04 Jun 2007 17:40:59 +0200
Post by Seweryn Habdank-Wojewódzki
A jakie jest merytoryczne uzasadnienie takiego konceptu?
Wszystko opisalem w poprzednich postach. Ten przyklad z niezkonczonym
zagniezdzeniem byl nie fortunny, co juz napisalem.
Seweryn Habdank-Wojewódzki
2007-06-05 00:23:36 UTC
Permalink
Witam
Post by Sulsa
On Mon, 04 Jun 2007 17:40:59 +0200
Post by Seweryn Habdank-Wojewódzki
A jakie jest merytoryczne uzasadnienie takiego konceptu?
Wszystko opisalem w poprzednich postach. Ten przyklad z niezkonczonym
zagniezdzeniem byl nie fortunny, co juz napisalem.
Nie. Nic nie napisałeś o projekcie. Napisałeś o plikach i podsumowałeś, że
projekt musiał się popsuć, bo masz molocha, a nie zgrabne klasy.

Pytam więc o projekt, czemu masz taką zależność.

Pozdrawiam.

Ps. Pimpl - http://www.gotw.ca/gotw/028.htm i
http://www.gotw.ca/gotw/024.htm
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Rafał Maj
2007-06-10 19:43:10 UTC
Permalink
Seweryn Habdank-Wojewódzki <f42a4v$i45$***@news.vectranet.pl> Tuesday, 5 June
2007 02:23
Post by Seweryn Habdank-Wojewódzki
Pytam więc o projekt, czemu masz taką zależność.
Pozdrawiam.
Ps. Pimpl - http://www.gotw.ca/gotw/028.htm i
http://www.gotw.ca/gotw/024.htm
Zresztą najprostszym rozwiązaniem jest po prostu by klasa A miała w sobie
wskaźnik na obiekt B i viceversa.
Seweryn Habdank-Wojewódzki
2007-06-10 19:48:19 UTC
Permalink
Witam
June 2007 02:23
Post by Seweryn Habdank-Wojewódzki
Pytam więc o projekt, czemu masz taką zależność.
Pozdrawiam.
Ps. Pimpl - http://www.gotw.ca/gotw/028.htm i
http://www.gotw.ca/gotw/024.htm
Zresztą najprostszym rozwiązaniem jest po prostu by klasa A miała w sobie
wskaźnik na obiekt B i viceversa.
Tak, ale OP taką sugestią pogardził.

Pozdrawiam.
--
|\/\/|   Seweryn Habdank-Wojewódzki
\/\/
Mateusz Loskot
2007-06-04 18:18:41 UTC
Permalink
Post by Sulsa
class B;
class A{
B b;
};
class B{
A a;
};
prompt > g++ a.cpp
a.cpp:4: error: field 'b' has incomplete type
no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
Nie da się, bo kompletność typu jest w takim wypadku obligatoryjna.
Jak mi mama mawiała "wyżej tyłka nie podskoczysz"

Pozdrawiam
--
Mateusz Loskot
http://mateusz.loskot.net
Jacek Czerwinski
2007-06-04 19:20:16 UTC
Permalink
Post by Sulsa
class B;
class A{
B b;
};
class B{
A a;
};
prompt > g++ a.cpp
a.cpp:4: error: field 'b' has incomplete type
no wlasnie da sie cos z tym zrobic - nie chce miec w tych klasach
wskaznikow ani referencji, tylko obiekty.
Możesz to powiedzieć na konkretach, nie na A i B?
Co to 'w życiu' ma być?

Podał ci Qurczak przykład o pudełkach...
Rafał Maj
2007-06-08 18:13:32 UTC
Permalink
Post by Sulsa
class B;
class A{
B b;
};
class B{
A a;
};
O, Parabox!

Prof. Farnsworth byłby zachwycony.
Kontynuuj czytanie narkive:
Loading...