2016-09-12 21 views
5

Nicol Bolas napisał w his answer w SO:Dlaczego kod wymagał dostępnego konstruktora kopiowania/przenoszenia, nawet jeśli pozwolono na kopiowanie?

Kopiowanie elizja wolno było się zdarzyć pod szeregu okoliczności. Jednak nawet jeśli było to dozwolone, kod nadal musiał być w stanie działać tak, jakby kopia nie została usunięta. Mianowicie, nie musiał być dostępny kopiowania i/lub przenieść konstruktora.]

Dlaczego było to konieczne (przed pojawieniem się „gwarantowanej kopiowania elizji”) dla kodu do utrzymania konstruktora kopia/ruch, nawet jeśli pozwolenie na kopiowanie było dozwolone?

Dlaczego "guaranteed copy elision" uwolnić programistę od tych wymagań?

Odpowiedz

1

Aby kod był gwarantowany, musi działać w dowolny sposób bez kopiowania w przypadku każdego przypadku, w którym nie jest gwarantowane kopiowanie.

1

Ponieważ był dozwolony, ale nie gwarantowany.

Jeśli dostępny konstruktor kopiowania nie jest wymagany, część kodu zostanie skompilowana po uruchomieniu optymalizacji, ale może się nie powieść w przypadku innego kompilatora.

+0

Dlaczego drugi kompilator nie wykonałby elizacji kopiowania, kiedy to się wydarzy? –

+1

Mogło, ale nie było wymagane. Być może było to "trudne" w niektórych przypadkach? W każdym razie była tam reguła, aby kompilator działał w obu kierunkach. –

+1

@WakeupBrazil Standardowa komisja C++ jest * bardzo * ostrożna w podejmowaniu decyzji. Mogły istnieć nieprzewidziane przypadki, w których kopiowanie byłoby pesymizacją, więc pozostawili wybór kompilatorowi. W C++ 17, z dodatkowym doświadczeniem, zdecydowali, że szanse na to wydarzenie są znikome, więc w razie potrzeby zostanie zapewniona zgoda na kopiowanie. – Quentin

3

Gdy wymóg kopiowania jest/nie był gwarantowany (lub wymagany) przez standard, nie ma wymogu, aby kompilator go zaimplementował.

Oznaczało to, że standardowe kompilatory mogą obsługiwać kopiowanie, ale nie wymagały tego. W praktyce pewna liczba dostawców kompilatorów zdecydowała się nie wdrażać funkcji kopiowania. Dla tych sprzedawców jest to kwestia kosztów - brak implementacji funkcji pochłania mniej wysiłku programistów. Dla programistów (osób używających kompilatorów) była to kwestia jakości wdrożenia - kompilator wyższej jakości był bardziej skłonny do wprowadzania pożądanych optymalizacji, w tym kopiowej elizacji, niż kompilator o niższej jakości - ale także droższy w pozyskiwaniu.

Z biegiem czasu, ponieważ kompilatory wyższej jakości stają się swobodniej dostępne (przez różne definicje "bezpłatne" - nie wszystkie są równoważne zerowym kosztom), stopniowo standard jest w stanie wydać więcej funkcji, które wcześniej były opcjonalne. Ale tak się nie zaczęło.

Z opcjonalną kopią niektóre kompilatory bazowałyby na dostępności odpowiednich konstruktorów kopii itp., A niektóre nie. Jednak pojęcie kodu, które spełnia wymagania normy, budowane za pomocą jednego zgodnego kompilatora, ale nie innego, jest naturalnie niepożądane w standardzie. W związku z tym w standardzie zalecono, aby konstruktorzy byli dostępni, nawet jeśli zezwalają na ich usunięcie.

+0

Posiadanie kodu akceptowanego przez niektóre kompilatory, ale nie przez inne, powinno być uważane za znacznie mniej niepożądane niż kod, który jest akceptowany przez wszystkie kompilatory, ale ma inne znaczenie. Zestaw zadań, które mogłyby zostać wykonane przez programy, które mogą zostać odrzucone przez niektóre (lub nawet większość) implementacje, ale nie wywoływał UB w żadnej implementacji, która je zaakceptowała, byłby znacznie większy niż zestaw zadań, które można by pomyślnie wykonać na wszystkich wdrożenia. IMHO, Standard powinien określać kategorię dla takich programów i dążyć do maksymalizacji liczby zadań, które mogą wykonać. – supercat

+0

Może tak, supercat. Ale moja odpowiedź dotyczy logiki stojącej za tym, czego wymaga standard (tzn. Kod, który kompiluje się z jedną zgodną ze standardem implementacją, nie powinien zawieść w kompilacji z inną zgodną z normą implementacją). Jeśli uważasz, że przesłanka ta wymaga zmiany, podejmij ją w komisji normalizacyjnej - zgodzili się, aby działała w ten sposób, a nie ja. – Peter

+0

Wiele zadań nie może być wydajnie wykonywanych bez użycia funkcji, które mogą być łatwo obsługiwane w 99%, ale nie w 100% % platform. We wczesnych komitetach normalizacyjnych nie starano się zdefiniować wszystkiego, czego potrzeba językowi, aby skutecznie wykonywać zadania na 90% platform, a jedynie rzeczy, które mogą być obsługiwane w 100%. Nigdy nie "zgodzili się", że takie funkcje nie powinny być wspierane na 90% platform, na których byłoby to użyteczne i tanie. – supercat

0

Dlaczego konieczne było (przed pojawieniem się "gwarantowanej zgody na kopiowanie"), aby kod zachował konstruktora kopiowania/przenoszenia, nawet jeśli pozwolono na kopiowanie?

Bo jak mówili inni, to właśnie jest dozwolone, że skopiować lub ruch został pominięty. Nie każdy kompilator musiał to pominąć, więc dla zachowania spójności programista nadal umożliwiał kopiowanie/przenoszenie. I konceptualnie wciąż istniała kopia/ruch, niezależnie od tego, czy kompilator wykonał, czy nie, to inna historia.

Dlaczego "gwarantowana metoda kopiowania" zwalnia programistę z tych wymagań?

Ponieważ na początku nie ma kopii ani przeniesienia. Gwarantowana kopia "elision" działa przez całkowitą zmianę znaczenia T a = T(), mówiąc, że T() inicjuje zamiast obiektu tymczasowego obiekt, dlatego konstruktorzy kopiowania lub przenoszenia w żadnym momencie nie stanowią nawet części gry.