Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Kopírovací a přesouvací algoritmy v C++
18. ledna 2002, 00.00 | V dnešním článku si ukážeme jak lze jednoduše v C++ odstranit data, nebo kopírovat data mezi libovolnými kontejnery z knihovny STL. Vše lze i mezi obyčejnými poli, nebo datovými proudy. Pro tuto činnost je v STL dispozici několik šablon funkcí.
V minulém článku jsme se dověděli, že standardní knihovna jazyka C++ má k dispozici mnoho užitečných šablon funkcí. Mnoho z nich manipuluje s kontejnery pomocí iterátorů (Viz můj článek "Iterátory v C++"). Dnes se podrobněji podíváme na kopírovací a přesouvací algoritmy.
Kopírovací algoritmy v C++Ke kopírování dat slouží algoritmy copy a copy_backward.
Parametry šablony copy jsou typy vstupních a výstupních iterátorů. Parametry funkce jsou iterátory na
začátek a konec zdrojové oblasti. Třetím parametrem je iterátor na začátek cílové oblasti. Deklarace je následující:
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator zacatek, InputIterator konec, OutputIterator cil)
Algoritmus zkopíruje data počínaje prvkem, na který se odkazuje zacatek a konče prvkem daným iterátorem konec na pozici
danou iterátorem cil. Funkce vrací iterátor na poslední zkopírovaný prvek. Algoritmus copy_backward je obdobný.
S tím rozdílem, že parametry šablony jsou obousměrné iterátory (Viz můj článek Iterátory v C++.), a data se
kopírují "od zadu". Je dobré si uvědomit, že všude, kde je možné použit iterátor, lze použít také ukazatel. A také datové proudy mají iterátory.
Nyní jednoduchý příklad.
|
Postupně kopírujeme data mezi vektorem a polem. Mezi vektorem a datovým proudem cout, mezi polem a proudem cout atd... Tímto příkladem se můžeme také přesvědčit, že kopírovat lze mezi libovolnými kontejnery jako vektor, nebo množina (Viz můj článek "Množina a multimnožina v C++"). Ale také mezi datovými proudy, nebo poli. Pokud budeme kopírovat prvky na standardní výstup pomocí iterátoru datového proudu, narazíme na jednu nepříjemnost. Oddělovací znak bude vložen i za poslední číslo. To může být někdy nežádoucí (například zde, když na stdout je za posledním číslem znak ','), jindy zase ano (například v souboru Pokus.txt je dobré mít za posledním číslem nový řádek).
Přesouvací algoritmy v C++Pod pojmem přesun si každý představí smazání dat v jednom kontejneru, a vytvoření těchto dat v kontejneru jiném. Problém je v tom, že takto se algoritmy, které chci popsat nechovají. Slovo "přesouvací" je můj dosti nevhodný překlad slova remove. Nenapadá mne ale žádné jiné slovo, kterým by se dala činnost "remove" algoritmů popsat. Algoritmy remove a remove_if prvky z kontejneru odstraní. Data nebudou nikam přesunuta. Zde bych chápal význam slova remove jako odstranit. Ale algoritmy remove_copy a remove_copy_if ani nepřesouvají ani neodstraňují. Nezabývejme se ale názvem článku, a pojďme se podívat na činnost těchto algoritmů. Deklarace šablon:
- template <class InputIterator, class OutputIterator, class Typ> OutputIterator remove_copy (InputIterator zacatek, InputIterator konec, OutputIterator vysledek, const Typ& hodnota) - V oblasti dané iterátory zacatek a konec vybere všechny prvky, které NEjsou rovny s prvkem hodnota. Porovnání bude provedeno operátorem != , který je buď implicitní, nebo jej musíme přetížit. Tyto prvky zkopíruje do jiného kontejneru na pozici danou iterátorem vysledek. Původní kontejner se nijak nezmění.
- template <class InputIterator, class OutputIterator, class TFunkcniObjekt> OutputIterator remove_copy_if (InputIterator zacatek, InputIterator konec, OutputIterator vysledek, TFunkcniObjekt podminka) - Vybere v oblasti dané iterátory zacatek a konec všechny prvky, které NEvyhovují podmínce (NEplatí podminka(*i) == true, kde i je iterátor v rozsahu zacatek až konec). Tyto prvky zkopíruje do kontejneru na pozici danou iterátorem vysledek. Původní kontejner se nijak nezmění.
- template <class ForwardIterator, class Typ> ForwardIterator remove (ForwardIterator zacatek, ForwardIterator konec, const Typ &hodnota); - Obdobný algoritmus jako remove_copy s tím rozdílem, že vybrané prvky budou z kontejneru odstraněny. Nebudou nikam přesunuty ani zkopírovány. Odstraněny budou prvky, které jsou si rovny s daným prvkem.
- template <class ForwardIterator, class TFunkcniObjekt> ForwardIterator remove_if (ForwardIterator zacatek, ForwardIterator konec, TFunkcniObjekt podminka); - Obdobný algoritmus jako remove_copy_if s tím rozdílem, že vybrané prvky budou z kontejneru odstraněny. Nebudou nikam přesunuty ani zkopírovány. Odstraněny budou prvky, pro které platí podmínka.
Algoritmy remove a remove_if nijak nemění velikost kontejneru. Jejich návratová hodnota je iterátor na poslední platný prvek v kontejneru po provedení algoritmu. Je vhodné zbytek kontejneru (od tohoto iterátoru až po konec) smazat. NEZAPOMEŇTE na to! Je to zdrojem častých chyb. Vše je znázorněno v příkladu. V příkladu je použita šablona třídy unary_compose, která slouží ke "skládání" funkcí, nebo funkčních objektů. Parametry šablony jsou dva typy unárních funkcí, nebo třídy unárních funkčních objektů. Konstruktoru předám dva ukazatele na unární funkci, nebo unární funkční objekty. Výsledkem volání operátoru () instanci třídy unary_compose je volání O1(O2(x)), kde x je parametr operátoru (), O1 a O2 jsou funkce, nebo funkční objekty dané konstruktoru. Příklad:
|
Všimněte si, jak jsem pouze pomocí standardních prostředků C++ "složil" funkční objekt delitelne_10. Použil jsem při tom standardní funkční objekty.
Příště se podíváme na vyhledávácí algoritmy.
Obsah seriálu (více o seriálu):
- Základy OOP v C++: Od C k C++
- Základní pojmy objektově orientovaného programování
- Vytváření tříd, instance třídy, zasílání zpráv v C++
- Vytváření instancí - konstruktory, destruktory
- Kopírovací konstruktor v C++
- Jednoduchá dědičnost v C++
- Časná versus pozdní vazba - úvod do polymorfismu v C++
- Polymorfismus - dokončení
- Vícenásobná dědičnost v C++
- Vícenásobná dědičnost v C++ - opakovaná dědičnost
- Vícenásobná dědičnost v C++ - volání konstruktorů a destruktorů
- Přetěžování operátorů v C++ 1.díl
- Přetěžování operátorů v C++ 2. díl
- Vstupní a výstupní operace pomocí datových proudů v C++
- Přetěžování operátorů << a >> pro datové proudy v C++
- Neformátovaný vstup a výstup v C++
- Paměťové proudy v C++
- Prostory jmen v C++
- Řetězce v C++
- Výjimky v C++
- Výjimky v C++ - výjimky tvoří dědičnou hierarchii
- Výjimky v C++ - dokončení
- Dynamická identifikace typů v C++
- Přetypování v C++
- Problémy s typy při vícenásobné dědičnosti
- Šablony funkcí v C++
- Šablony datových typů v C++
- Vnitřní typy u parametrů šablon, vnořené šablony v C++
- Pole s libovolným intervalem indexování v C++
- Datové kontejnery v C++ - Úvod do STL
- Vector - datový kontejner v C++
- Iterátory v C++
- Šablona vector v C++ a iterátory
- Asociativní pole v C++
- Množina v C++
- Funkční objekty v C++
- Standardní funkční objekty v C++
- Úvod do standardních algoritmů v C++
- Kopírovací a přesouvací algoritmy v C++
- Vyhledávací algoritmy v C++
- Skenovací (prohlížecí) algoritmy v C++
- Transformační algoritmy v C++
- Řadící algoritmy v C++
- Halda v C++
- Standardní algoritmy v C++ - dokončení
- Automatické ukazatele v C++
- Inteligentní ukazatel - čítač referencí v C++
- Použití čítače referencí v C++
- Kopírování velkých objektů v C++
- Řízené kopírování prvků v poli v C++
- Dokončení seriálu objektově orientované programování v C++
Poslat článek
Nyní máte možnost poslat odkaz článku svým přátelům:
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007