[C++] Zagadkowe działanie kompilatora

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
Chmarus
Piegowaty Guziec
Piegowaty Guziec
Posty: 4
Rejestracja: 06 gru 2009, 15:02
Płeć: Mężczyzna
Wersja Ubuntu: 9.10
Środowisko graficzne: GNOME
Architektura: x86

[C++] Zagadkowe działanie kompilatora

Post autor: Chmarus »

Witam. Zauważyłem dziwne działanie kompilatora g++ na swoim ubunciaku. Uczę się trochę c++ i postanowiłem sobie przećwiczyć konstruktory kopiujące itp. Zrobiłem funkcję f1(), która tworzy obiekt, ustala wartość składowej po czym zwraca utworzony obiekt. Gdy wywołuję konstruktor kopiujący w sposób:

Kod: Zaznacz cały

X obiekcik = f1();


g++ wywala mi błąd, który sugeruje, że kompilator nie wie czy na dobrą sprawę ma skorzystać z domyślnego konstruktora czy z konstruktora kopiującego:

Kod: Zaznacz cały

main.cpp:34: error: no matching function for call to ‘X::X(X)’
main.cpp:20: note: candidates are: X::X(X&)
main.cpp:16: note:                 X::X()
Bład występuje tylko przy inicjalizacji w sposób jak napisałem wyżej. Gdy najpierw stworzę obiekt, a potem dopiero go przyrównam do f1() wszystko gra. Dodam, że takie wywołanie w pełni działa na Microsoft Visual 2010. Kwestia ustawienia stopnia "pedantyczności" kompilatora nie wchodzi w rachubę gdyż to już testowałem. Zdaję sobie sprawę, że takie czynności nie są potrzebne w praktycznym programowaniu ale ciekawi mnie to mimo wszystko :D Jak myślicie czemu tak jest?
www.mmorpg.org.pl - Portal o grach MMO
Awatar użytkownika
dawwin
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 202
Rejestracja: 18 kwie 2009, 09:16
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: GNOME
Architektura: x86
Kontakt:

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: dawwin »

gcc z tego, co ja zauważyłem wymaga w przypadku definiowania konstruktora kopiującego także tego bezargumantowego. Dlaczego? Z tego, co wywnioskowałem wynika to z tego powodu, że ja mogę nie chcieć tworzyć konstruktora bezargumentowego i w chwili zdefiniowania jakiegoś, który przyjmuje argumenty potrzeba też jawnie zdefiniować ten domyślny. W Twoim przypadku wystarczy zrobić takie coś w definicji twojej klasy

Kod: Zaznacz cały

x() {}
A to masz cały przykład napisany trochę na szybko przeze mnie

Kod: Zaznacz cały

#include <iostream>

using namespace std;

class abc {
	public:
		abc() {}
		abc(const abc &a) {
			this->a = a.a;
		}
		
		int a;
};

abc f()
{
	abc a;
	a.a = 7;
	return a;
}

int main()
{
	abc b = f();
	cout << b.a << endl;
	return 0;
}

Czyli wygląda na to, że visual jest pod tym względem trochę bardziej "przebiegły" i jest w stanie to sobie zautomatyzować
Moje programy - http://dawwin.users.sourceforge.net/
Nie pomagam na PW
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: luzakwielki »

@dawwin: W twoim wypadku po prostu nie skorzysta z konsktruktora tylko wygeneruje własny - zmień w kodzie konstruktor na np.:

Kod: Zaznacz cały

		abc(const abc &a) {
			this->a = 999;
		}
A dalej będziesz miał a == 7, żeby skorzystać z konstruktora kopiującego musiałbyś zmodyfikować to co zwraca funkcja:

Kod: Zaznacz cały

abc& f(){
	abc *a = new abc();
	a->a = 7;
	return *a;
}
Bez tego, zarówno VS, jak i GCC oleją to co napisałeś w funkcji i zrobią sobie własne konstruktory.
Awatar użytkownika
Hauleth
Wytworny Kaczor
Wytworny Kaczor
Posty: 382
Rejestracja: 18 sie 2008, 17:43
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: GNOME
Architektura: x86

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: Hauleth »

@luzakwielki - co to za funkcja jest LoL??
Jeśli problem rozwiązany dodaj na początku tematu [SOLVED].

Biblioteka do C++ - Bust Lib: http://code.google.com/p/bust/
mikolajs
Wytworny Kaczor
Wytworny Kaczor
Posty: 352
Rejestracja: 15 paź 2008, 18:30
Płeć: Mężczyzna
Wersja Ubuntu: 9.04
Środowisko graficzne: KDE Plasma

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: mikolajs »

Czyli wygląda na to, że visual jest pod tym względem trochę bardziej "przebiegły" i jest w stanie to sobie zautomatyzować
A wziąłeś pod uwagę fakt, że używanie konstruktora kopiującego na obiekcie stworzonym automatycznym konstruktorem jest nieco niebezpieczne, stąd może to być zabezpieczenie przed tego typu sytuacją. Dobrym pomysłem jest inicjowanie pól składowych klasy. Być może gcc dosłownie traktuje wytyczne aby tworzyć automatycznie konstruktor domyślny gdy nie ma innych? :)

Kod: Zaznacz cały

abc b = f();
Ciekaw jestem jak powyższy kod działa na VS? Użycie w tym przypadku konstruktora kopiującego byłoby błędem kompilatora. W funkcji powstały obiekt znika, przekazywana jest jego kopia. Nie ma więc mowy o przekazaniu referencji bo nie byłoby do czego się odwoływać. Sprawdź czy w VS poprawnie kopiuje dane z obiektu powstałego w funkcji, czy też może sięga do nieistniejącej już pamięci. Możliwe też, że kompilator wychwytuje sytuację odwoływania do nieistniejącego już obiektu i sam go jakoś przechowuje w pamięci do czasu używania. Ale to znowu byłoby to wyręczanie programisty i choć być może wygodne to jednak nie pozwala na zauważenie własnych błędów.
Co do rozwiązania Luzakwielkiego to trzeba by potem jakoś obiekt usunąć (np w konstruktorze kopiującym) z pamięci, a to już lepiej po prostu przekazać wskaźnik.
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: luzakwielki »

Hauleth pisze:@luzakwielki - co to za funkcja jest LoL??
Normalna? 8-)
mikolajs pisze:Co do rozwiązania Luzakwielkiego to trzeba by potem jakoś obiekt usunąć (np w konstruktorze kopiującym) z pamięci, a to już lepiej po prostu przekazać wskaźnik.
Jak wskaźnik przekażesz to też musisz usunąć z pamięci (np. w konstruktorze kopiującym), więc żadna różnica (poza tym, że musisz zmienić z "abc b = f();" na "abc b = *f();").
Awatar użytkownika
Hauleth
Wytworny Kaczor
Wytworny Kaczor
Posty: 382
Rejestracja: 18 sie 2008, 17:43
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: GNOME
Architektura: x86

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: Hauleth »

@luzakwielki, ale ona cieknie jak cholera a oprócz tego tak się nie robi!
Jeśli problem rozwiązany dodaj na początku tematu [SOLVED].

Biblioteka do C++ - Bust Lib: http://code.google.com/p/bust/
mikolajs
Wytworny Kaczor
Wytworny Kaczor
Posty: 352
Rejestracja: 15 paź 2008, 18:30
Płeć: Mężczyzna
Wersja Ubuntu: 9.04
Środowisko graficzne: KDE Plasma

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: mikolajs »

Jak wskaźnik przekażesz to też musisz usunąć z pamięci (np. w konstruktorze kopiującym), więc żadna różnica (poza tym, że musisz zmienić z "abc b = f();" na "abc b = *f();").
Miałem na myśli abc *b = f() czyli mamy factory :)
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: luzakwielki »

Hauleth pisze:@luzakwielki, ale ona cieknie jak cholera a oprócz tego tak się nie robi!
No pewnie, że cieknie (chyba, że) - jednak nie o tym jest wątek, tylko o konstruktorze kopiującym i żeby on zadziałał przy API takim jak chciał założyciel wątku "X obiekcik = f1();" musi zwracać referencję - zawartość funkcji była tylko modyfikacja tej podanej przez "dawwin", żeby działała z konstruktorem kopiującym - nie miałem zamiaru wgłębiać się w jaki sposób zarządza pamięcią, czy będzie robić fabryki, menadżery, singletony, czy inne wzrorce projektowe czy po prostu klasa abc będzie dziedziczyć po gc (dzięki czemu to new nie będzie new z C++, a z Boehm GC (który wchodzi w skład GCC), który sam zadba o odśmiecanie) - na prawdę mnie to w tym temacie nie obchodzi, bo nie to jest sensem tego tematu.
mikolajs pisze:Miałem na myśli abc *b = f() czyli mamy factory :)
Bądźmy zgodni z tematem - temat jest poświęcony nauce c++, a dokładniej konstruktorowi kopiującemu, a w ten sposób, który podałeś nie ma mowy o konstruktorze kopiującym, a przypisaniu wskaźnikowi b, adresu zwracanego przez funkcję czyli zupełnie nie o to chodzi.
mikolajs
Wytworny Kaczor
Wytworny Kaczor
Posty: 352
Rejestracja: 15 paź 2008, 18:30
Płeć: Mężczyzna
Wersja Ubuntu: 9.04
Środowisko graficzne: KDE Plasma

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: mikolajs »

Jasne - tylko tak ogólnie to cały przykład nie ma sensu i należy kolegę Chmarusa nakierować na sensowne rozwiązanie czyli wzorzec factory.
luzakwielki
Wytworny Kaczor
Wytworny Kaczor
Posty: 264
Rejestracja: 19 lis 2008, 11:42
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [C++] Zagadkowe działanie kompilatora

Post autor: luzakwielki »

mikolajs pisze:Jasne - tylko tak ogólnie to cały przykład nie ma sensu i należy kolegę Chmarusa nakierować na sensowne rozwiązanie czyli wzorzec factory.
Ja myślę, że nie trzeba nakierowywać, bo nie wiem czy to pierwszy język poznawany przez autora wątku, a autor też nie ma zamiaru tego wykorzystywać, tylko go Ciekawi co jak i dlaczego nie działa - na moje zdanie wpłynęło:
Chmarus pisze:Zdaję sobie sprawę, że takie czynności nie są potrzebne w praktycznym programowaniu ale ciekawi mnie to mimo wszystko :D Jak myślicie czemu tak jest?
Same wzorce projektowe itd to nauka programowania, a nie języka (są niezależne od języka), więc po prostu uznałem, że nie trzeba o nich pisać w tym temacie, bo nie o to w nim chodzi.
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 10 gości