Kurzusok
/
C++
C++
/
Feladatok
/
Troy ereje
Troy ereje

Troy ereje

Tanulófeladat

Bevezetés

Az auto kulcsszó C++-ban

A C++-ban az auto egy hatékony eszköz, amelyet a C++11 vezetett be: kikövetkeztetett adattípusú változók deklarálására szolgál. A fordító a változó típusát a kezdőértékéből következteti ki, amitől a kód olvashatóbbá és könnyebben karbantarthatóvá válik.

Példa a használatra

Nézzük a következő példát, amelyben az auto-val változókat deklarálunk:

auto dragon_population{3};          // dragon_population is deduced as an integer
auto westeros{7.7777};              // westeros is deduced as a double
auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string

Mindegyik esetben a változó típusát abból az értékből következteti ki a fordító, amellyel inicializáltuk.

Típuskövetkeztetés

Az auto kulcsszó segít tömörebb és olvashatóbb kódot írni, mert csökkenti a kifejezett típusok bőbeszédűségét.

const std::vector<std::string> pigeon_pie{"flour", "butter", "pigeon", "salt"};
auto purple_wedding_pie{pigeon_pie};
purple_wedding_pie.emplace_back("the strangler");

Ebben a ciklusban az auto a purple_wedding_pie típusát std::vector<std::string>-ként következteti ki, így nem kell újra kifejezetten megadni a típust.

Kompatibilitás

Az auto kulcsszó számos C++ szerkezettel működik együtt, ami sokoldalú eszközzé teszi a modern C++ programozásban.

auto& element{array[0]};           // reference to an element
const auto object{otherObject};    // const type version of otherObject's type
auto* ptr{&x};                     // pointer to x with the same type as x, but as a pointer.

A későbbi fogalmakban gyakran találkozunk majd az auto kulcsszóval lambda-kifejezésekkel, tartományalapú for-ciklusokkal és iterátorokkal.

Okos mutatók

Az okos mutatók modern C++-funkció, amely automatikus memóriakezelést nyújt, segítve a nyers mutatókhoz gyakran társított memóriaszivárgások és lógó mutatók megelőzését. Burkot képeznek a nyers mutatók körül, további funkciókat adva hozzájuk, például automatikusan felszabadítják a memóriát, amikor a mutatóra már nincs szükség.

Általános szintaxis

Az okos mutatókat általában osztálysablonként valósítják meg a C++ szabványos könyvtárában. A két leggyakrabban használt okos mutató a std::unique_ptr és a std::shared_ptr.

Egyedi mutatók

A std::unique_ptr olyan okos mutató, amely kizárólagosan birtokolja az objektumot. Biztosítja, hogy egy adott pillanatban csak egy std::unique_ptr objektum birtokolja az erőforrást. Amikor a birtokló std::unique_ptr megsemmisül vagy visszaáll, automatikusan megsemmisíti az objektumokat és felszabadítja a memóriájukat.

#include <memory>
// Declaring and defining a unique pointer
auto rightful_king_of_england = std::make_unique<std::string>("Excalibur");

// Unique pointers cannot be copied or assigned
auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr

A std::make_unique() előnyei

Amikor std::unique_ptr-t hozunk létre, érdemesebb a std::make_unique()-ot használni, ahelyett hogy közvetlenül a new-val foglalnánk memóriát. A std::make_unique() számos előnnyel jár:

  1. Kivételbiztonság: A std::make_unique() garantálja a kivételbiztonságot. Ha kivétel keletkezik az objektum létrehozása közben, a memória automatikusan felszabadul, megelőzve a memóriaszivárgást.
  2. Átláthatóság: A std::make_unique() használata világosabbá és tömörebbé teszi a kódot. Nem kell kifejezetten megadni a lefoglalandó típust, mert a sablonargumentumok automatikusan kikövetkeztethetők.
  3. Optimalizálási lehetőségek: A fordítóknak lehetőségük van hatékonyabban optimalizálni a std::make_unique()-ot, mint a new-val kézzel foglalt memóriát, ami jobb teljesítményt eredményezhet.
  4. A helytelen használat elkerülése: Lehetőség van az alapul szolgáló erőforrás törlésére, ha a std::unique_ptr-t kézzel hozzuk létre. Ez nem definiált viselkedéshez vezet, amikor a std::unique_ptr a scope végén megpróbálja törölni.

Megosztott mutatók

A std::shared_ptr olyan okos mutató, amely lehetővé teszi, hogy több std::shared_ptr objektum megossza ugyanazon erőforrás tulajdonjogát. Számon tartja, hogy hány megosztott mutató hivatkozik az erőforrásra, és csak akkor szabadítja fel a memóriát, amikor az erőforrást birtokló utolsó megosztott mutató kikerül a scope-ból vagy visszaáll.

// Declaring and defining a shared pointer to a dynamically allocated string
auto martian_congressional_republic = std::make_shared<std::string>("protomolecule");

// Creating more shared pointer that shares ownership
auto outer_planets_alliance = martian_congressional_republic;
auto united_nations = martian_congressional_republic;
Caution

A C++17-ben és korábbi verziókban a std::shared_ptr tömbökkel való használata a std::make_shared<T[]>-on keresztül nem támogatott közvetlenül. Bár lehetséges tömböket foglalni a std::make_shared<T[]>-val, a belőlük közvetlenül létrehozott megosztott mutatók nem definiált viselkedéshez vezethetnek, mivel az egyes objektumok és a tömbök memóriakezelése eltér. Ehelyett érdemes std::vector-t vagy egyéni törlőfüggvényeket használni a tömbök hatékony kezelésére megosztott mutatókkal. A C++17-ben a tömbkiosztások és a megosztott mutatók kezelésekor mindig győződj meg a fordítóval és a szabványos könyvtár implementációjával való kompatibilitásról.

A std::make_shared() előnyei

A std::make_unique()-hoz hasonlóan a std::make_shared() is olyan előnyöket kínál, mint a jobb memóriahatékonyság, a kivételbiztonság és az olvashatóság. A vezérlőblokk és a kezelt objektum memóriafoglalását egyetlen műveletbe vonja össze, ami növeli a hatékonyságot és csökkenti a memóriaszivárgás kockázatát. Ráadásul a sablonargumentumok automatikus kikövetkeztetése egyszerűbbé teszi a kódot és javítja az olvashatóságát. A std::make_shared() használata tisztább, biztonságosabb és hatékonyabb kódot eredményez, amikor C++-ban std::shared_ptr objektumokkal dolgozunk.

Használati tanácsok

Alapértelmezés szerint használj okos mutatókat: std::unique_ptr-t a kizárólagos tulajdonjoghoz és std::shared_ptr-t a megosztott tulajdonjoghoz. A nyers mutatókat a nem birtokló hivatkozásokhoz, illetve a régi kóddal való kapcsolódáshoz tartsd fenn. A legtöbb esetben a std::unique_ptr elegendő a kizárólagos tulajdonjoghoz, mert könnyűsúlyú memóriakezelést kínál a referenciaszámlálás többletterhe nélkül. A std::shared_ptr-t takarékosan érdemes használni, mert többletterhet és bonyolultságot hoz, hacsak nem valódi megosztott tulajdonjogra van szükség.

Utasítások

Ez a feladat Trója világába kalauzol el. Lakóinak élete csupa csoda és varázslat. Trója sok lakója képességekkel rendelkezik, amelyeket a mindennapjaiban gyakran használ. A képességekkel formálják át a világot, vagy befolyásolják Trója élővilágát és más embereket. A mágia emellett egyedi ereklyékben is megnyilvánul, amelyekre kalandorok, mesteremberek és bölcsek egyaránt áhítoznak.

Ebben a feladatban kódot írsz, amely Trója lakóit, a birtokukban lévő ereklyéket és a képességek kölcsönhatásait modellezi.

Hat részfeladat vár rád. Az első egy ember létrehozásáról szól, a másik öt a képességek és az ereklyék kezeléséről.

1. Hozd el az embereket Trója világába

A trójai modelledben az emberek a legfontosabbak. A modelledben szereplő embernek egyedi ereklyét kell birtokolnia. Emellett képességet is meg kell tudnia idézni. Ezek a képességek hatással lehetnek más emberekre, ezért azt is modellezned kell, hogy egy ember áll-e valamely más képesség hatása alatt.

Az artifact és a power struktúra alapvető implementációját előre megkapod. Készíts egy human struktúrát (vagy osztályt), amelynek van egy possession nevű artifact tagváltozójára mutató okos mutatója. Egy ereklyét egy adott pillanatban csak egyetlen ember birtokolhat.

A human-nek két további tagváltozóval kell rendelkeznie. Az egyik a saját own_power-ét tárolja, a másik pedig azt a képességet, amelynek a hatása alatt áll (influenced_by). Az own_power és az influenced_by is egy-egy power objektumra mutató okos mutató. Egy power objektumot egyszerre csak egyetlen ember birtokolhat, ugyanakkor más emberekre is hathat.

Alapértelmezés szerint az emberek ereklye nélkül születnek, és sem képességük nincs, sem annak hatása alatt nem állnak.

human mindy_mccready{};
mindy_mccready.possession;
// => nullptr
mindy_mccready.own_power;
// => nullptr
mindy_mccready.influenced_by;
// => nullptr

2. Hozd be az ereklyéket Trójába

A modelled unalmas, ha az elemei nem lépnek kölcsönhatásba egymással. Egyedi ereklyéket szeretnél létrehozni, és odaadni őket bizonyos embereknek.

Definiáld a give_new_artifact függvényt, amely nem ad vissza semmit, paraméterként viszont egy human referenciáját és egy string-et kap. A string-ből hozzon létre egy új artifact objektumot, és állítsa be annak megfelelően a human possession mutatóját. A függvény ne adjon vissza semmit.

human erik_magnus_lehnsherr{};
give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet");

erik_magnus_lehnsherr.possession->name;
// "Mind shielding helmet"

3. Tedd cserélhetővé a tárgyakat

Trója világában minden a kölcsönhatásról szól. Szeretnéd, ha az emberek a birtokaik elcserélésével kereskednének.

Írj egy exchange_artifacts függvényt, amely nem ad vissza semmit, hanem két, ereklyére mutató okos mutatót kap, hogy elcserélje a tárgyakat. Ne feledd, hogy egy unique_ptr-t nem lehet lemásolni. Ez a függvényparaméterekre is vonatkozik. Helyette a unique_ptr referenciáját használd.

human uchiha{};
give_new_artifact(uchiha, "konoha headband");
human uzumaki{};
give_new_artifact(uzumaki, "forehead protector");

exchange_artifacts(uchiha.possession, uzumaki.possession);

uchiha.possession->name;
// "forehead protector"
uzumaki.possession->name;
// "konoha headband"

4. Adj képességeket az embereknek

Trója legizgalmasabb vonásai a különleges képességek, amelyeket az emberek birtokolhatnak. Egyesek a gondolataikkal olvasztanak vasat, mások éjszaka azonnal begyógyítanak minden sebet.

Definiáld a manifest_power függvényt, amely nem ad vissza semmit, paraméterként viszont egy human referenciáját és egy string-et kap. A string-ből hozzon létre egy új powers objektumot, és állítsa be annak megfelelően a human own_power mutatóját. A függvény ne adjon vissza semmit.

human eleven {};
manifest_power(eleven, "psychokinesis");

eleven.own_power->effect;
// "psychokinesis"

5. Használd a képességet

Mit érnek a legnagyobb képességek, ha nem tudod használni őket? A modelled az emberekre összpontosít, ezért követned kell a képességek hatását.

Írj egy void use_power függvényt, amely két ember referenciáját kapja. Az első ember a képesség kibocsátója, a második pedig a célpont. A célpont influenced_by mutatója a kibocsátó képességére mutasson.

Az egyszerűség kedvéért egy ember egyszerre csak egyetlen képesség hatása alatt állhat. Ez a képesség a helyén marad akkor is, ha a kibocsátó már nem létezik.

human pamela_isley{};
manifest_power(pamela_isley, "control pheromones");

human count_vertigo{};
use_power(pamela_isley, count_vertigo);
count_vertigo.influenced_by->effect;
// "control pheromones"

6. Tartsd szemmel a képesség intenzitását

Bizonyos képességek elveszítik hatásukat, vagy meghatározott hatásokat váltanak ki a szimulációdban, amikor több emberre alkalmazzák őket. Követned kell, hány ember kapcsolódik az egyes képességekhez.

Definiáld a power_intensity függvényt, amely egy embert kap, és a képessége intenzitását int-ként adja vissza. Ha az illetőnek nincs képessége, a visszatérési érték 0 legyen. Egyébként az intenzitásnak tükröznie kell a képesség kibocsátóját és mindenkit, aki jelenleg a hatása alatt áll.

human jean_grey{};
manifest_power(jean_grey, "uplifting personality");

human scott{};
human logan{};
human ororo{};

use_power(jean_grey, ororo);
use_power(jean_grey, logan);
use_power(jean_grey, scott);

power_intensity(jean_grey);
// 4
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
C++ Exercism

Készen állsz elkezdeni a(z) Troy ereje feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) C++ nyelvet 19 fogalom100 feladat segítségével, valódi emberi mentorálással, mindez ingyen.