Másolat konstruktor

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2015. március 31-én felülvizsgált verziótól ; az ellenőrzések 16 szerkesztést igényelnek .

A másoláskonstruktor egy speciális konstruktor a  C++ programozási nyelvben és néhány más programozási nyelvben, például a Java -ban, amelyet egy új objektum létrehozására használnak egy meglévő másolataként . Egy ilyen konstruktor legalább egy argumentumot használ: egy hivatkozást a másolandó objektumra.

Normális esetben a fordító minden osztályhoz automatikusan generál egy másolatkonstruktort ( implicit copy konstruktornak nevezik, azaz implicit módon megadott másoláskonstruktornak), de bizonyos esetekben a programozó létrehoz egy másolatkonstruktort, amelyet ezután explicitnek neveznek. másolás konstruktor (vagy "explicit módon megadott másolás konstruktor"). módon"). Ilyen esetekben a fordító nem generál implicit konstruktorokat.

A másoláskonstruktorra leginkább akkor van szükség, ha az objektum mutatót vagy nem megosztott hivatkozást tartalmaz, például fájlt , ebben az esetben általában szükség lesz egy destruktorra és egy hozzárendelési operátorra is (lásd a három szabályt ).

Definíció

Az objektumok másolása a másoláskonstruktor és a hozzárendelés operátor használatával történik . A másoláskonstruktor első paramétereként (az opcionális const vagy volatile type módosítóval) a saját osztálytípusára való hivatkozást veszi. Ezen a paraméteren kívül további további paraméterek is lehetnek, feltéve, hogy az ilyen további paraméterek alapértelmezett értékekre vannak állítva [1] . A következő példa bemutatja az X osztály érvényes másolatkonstruktorait:

X ( const X & ); X ( X & ); X ( const volatile X & ); X ( illékony X & ); X ( const X & , int = 10 ); X ( const X & , double = 1,0 , int = 40 );

A másoláskonstruktor első bejegyzése az elsődleges, más űrlapokat csak szükség esetén szabad használni. Csak ideiglenes objektumokat másolhat az első konstruktor használatával. Például:

Xa = X ( ); // Lefordítja, ha az X(const X&) konstruktor implementálva van, és hibát dob, // ha csak X(X&) van megadva. // Az a objektum létrehozásához a fordító létrehoz egy // X osztályú ideiglenes objektumot, majd a copy konstruktor segítségével létrehoz egy a objektumot. // Ideiglenes objektumok másolásához const típus szükséges.

Az alábbi példában az a objektum megváltoztathatatlanként van létrehozva, így a b objektum létrehozásakor az első példány konstruktorra van szükség.

const X a ; X b = a ; // helyes, ha van X(const X&) és nem helyes, ha van X(X&) // mivel a második nem támogatja a const X& típust

A X&másolás konstruktor típust akkor használjuk, ha módosítani kell a másolandó objektumot. Ez meglehetősen ritka helyzet, de a szabványos könyvtárban a hívással elérhető std::auto_ptr. A linknek meg kell valósítania:

Xa ; _ X b = a ; // javítsa ki, ha a másoláskonstruktorok bármelyike ​​definiálva van // a hivatkozás átadása óta

A következő másoláskonstruktorok (vagy konstans konstruktorok) érvénytelenek:

X ( X ); X ( állandó X );

mivel ezeknek a konstruktoroknak a meghívásához egy másik másolatra lesz szükség, ami egy végtelen rekurzív híváshoz (vagyis egy végtelen ciklushoz) vezet.

A másoláskonstruktor meghívásának négy esete van:

  1. Amikor egy objektum visszatérési érték
  2. Amikor egy objektumot argumentumként értékkel adunk át (egy függvénynek).
  3. Amikor egy objektumot egy másik objektumból (ugyanabban az osztályban) építenek fel
  4. Amikor a fordító létrehoz egy ideiglenes objektumot (mint a fenti első és második esetben; explicit konverzióként stb.)

Műveletek

Egy objektumhoz kétféleképpen lehet értéket rendelni:

  • Explicit hozzárendelés egy kifejezésben
  • Inicializálás

Explicit hozzárendelés egy kifejezésben

A objektum ; B objektum ; A = B ; // lefordítva: Object::operator=(const Object&), // így hívja meg az A.operator=(B)

Inicializálás

Egy objektum inicializálása a következő módok bármelyikén lehetséges:

a. Inicializálás a nyilatkozatnál

B objektum = A ; // lefordítva: Object::Object(const Object&)

b. Inicializálás argumentumok függvényeknek való átadásakor

típusfüggvény ( Object a ) ;

c. Amikor függvényértéket ad vissza

Objektum a = függvény ();

A másoláskonstruktor csak inicializálás esetén használatos, és nem egy kifejezett hozzárendelés helyett (vagyis ahol a hozzárendelési operátort használják ).

Az implicit osztálymásolat konstruktor meghívja az alaposztályok másoláskonstruktorait, és bitenkénti másolatokat készít az osztálytagokról. Ha egy osztálytag egy osztály, akkor a másolat konstruktora meghívásra kerül. Ha skalár típusú (POD típusú C++-ban), akkor a beépített hozzárendelési operátort használjuk. És végül, ha egy tömbről van szó, akkor a tömb minden elemét a típusának megfelelő módon másoljuk. [2]

Egy explicit másoláskonstruktor használatával a programozó meghatározhatja, hogy mit tegyen az objektum másolása után.

Példák

A következő példák bemutatják, hogyan működnek a másoláskonstruktorok, és miért van szükség rájuk.

Az implicit másolat konstruktor

#include <iostream> osztályú személy { nyilvános : int kor ; Személy ( belső életkor ) : életkor ( életkor ) {} }; int main () { személy timmy ( 10 ); személy sally ( 15 ); Személy timmy_clone = timmy ; std :: cout << timmy . kor << " " << Sally . kor << " " << timmy_clone . kor << std :: endl ; Timmy . életkor = 23 év ; std :: cout << timmy . kor << " " << Sally . kor << " " << timmy_clone . kor << std :: endl ; }

Eredmény

10 15 10 23 15 10

Ahogy az várható volt, a timmy át lett másolva az új timmy_clone objektumba . A timmy korának (korának) megváltoztatásakor a timmy_clone kora nem változott: az objektumok teljesen függetlenek.

A fordító generált nekünk egy másolás konstruktort, ami valahogy így írható:

Személy ( Person Const & Copy ) : kor ( példány . kor ) {}

Explicit másolat konstruktor

A következő példa egy egyszerű dinamikus tömbosztályt mutat be:

#include <iostream> osztály Array { nyilvános : mérete ; _ int * adatok ; Tömb ( belső méret ) : méret ( méret ), adatok ( új int [ méret ]) {} ~ Tömb () { töröl [] adatot ; } }; int main () { Először a tömb ( 20 ); először . adat [ 0 ] = 25 ; { Tömb másolat = első ; std :: cout << first . adat [ 0 ] << " " << másolás . adat [ 0 ] << std :: endl ; } // (1) először . adat [ 0 ] = 10 ; // (2) }

Eredmény

25 25 felosztási hiba

Itt a fordító automatikusan generálta a másolás konstruktort. Ez a konstruktor így néz ki:

Tömb ( Tömb állítása és másolása ) : méret ( másolat . méret ), adat ( másolat . adat ) {}

Ezzel a konstruktorral az a probléma, hogy egyszerű másolatot készít az adatmutatóról . Csak a címet másolja, magát az adatot nem. És amikor a program eléri az (1) sort, a másolás destruktor meghívódik (a veremben lévő objektumok automatikusan megsemmisülnek, amikor elérik a határukat). Amint láthatja, az Array destruktor törli az adattömböt , így a másolat adatainak törlésekor az első adatot is törli . A (2) sor most hibás adatokat fogad és kiírja. Ez a híres szegmentációs hibához vezet.

Egy mélymásolást végrehajtó natív másoláskonstruktor esetén ez a probléma nem fog fellépni:

Tömb ( Tömb állítása és másolása ) : méret ( másolat . méret ), adat ( új int [ másolat . méret ]) { std :: másolás ( másolás . adat , másolás . adat + másolat . méret , adat ); // #include <algoritm> for std::copy }

Itt egy új int tömb jön létre , és a tartalom belemásolódik. Most a másolás destruktora csak az adatait távolítja el, és nem érinti meg az első adatot . A (2) vonal már nem okoz szegmentációs hibát.

A mélymásolás végrehajtása helyett többféle optimalizálási stratégia is használható. Ez lehetővé teszi több objektum adathozzáférését biztonságos módon, így memóriát takarít meg. A másolás írásra stratégia csak akkor hoz létre másolatot az adatokról, amikor azokba írják. A hivatkozási szám tartalmazza az adatokra hivatkozó objektumok számának számlálóját, és csak akkor távolítja el, ha a számláló eléri a nullát (például boost::shared_ptr).

Konstruktorok és sablonok másolása

A sablonkonstruktor nem másoláskonstruktor .

sablon < típusnév T > Tömb :: Tömb ( const T & copy ) : méret ( másolat . méret ()), adatok ( új int [ másolat . méret ()]) { std :: másolás ( másolás . kezdete (), másolás . vége (), adat ); }

Ez a konstruktor nem kerül felhasználásra, ha a T Tömb típusú.

Array arr ( 5 ); Array arr2 ( arr );

A második sor meghívja a nem sablon másoláskonstruktort, vagy ha nem létezik, akkor az alapértelmezett másolatkonstruktort.

Lásd még

Jegyzetek

  1. INCITS ISO IEC 14882-2003 12.8.2. [1] Archiválva : 2007. június 8. a Wayback Machine -nél
  2. INCITS ISO IEC 14882-2003 12.8.8. [2] Archiválva : 2007. június 8. a Wayback Machine -nél