Bude seznam inicializace vždy zpracovány před konstruktoru kód?

hlasů
10

Bude seznam inicializace vždy zpracovány před konstruktoru kód?

Jinými slovy, bude následující kód vždy vytisknout <unknown>, a početně třída bude mít „známé“, jak je hodnota source_(v případě, že globální proměnná somethingje true)?

class Foo {
  std::string source_;
public:
  Foo() : source_(<unknown>) {
    std::cout << source_ << std::endl;
    if(something){
      source_ = known;
    }
  }
};
Položena 07/04/2009 v 03:29
zdroj uživatelem
V jiných jazycích...                            


3 odpovědí

hlasů
13

Ano, to bude, dle C++11: 12.6.2.

Hlavním důvodem pro použití init-seznamů je pomoci kompilátoru s optimalizací. Init-seznamy pro non-základních typů (tj třída objektů spíše než int, floatatd), mohou být obecně konstruovány na místě.

Vytvoříte-li objekt přiřadit k ní v konstruktoru, to obecně vede ke vzniku a zániku dočasných objektů, což je neefektivní.

Init-seznamy mohou se vyhnout (v případě, že kompilátor je k ní, samozřejmě, ale většina z nich by mělo být).

Následující kompletní program bude výstup 7, ale to je pro konkrétní překladač (cygwin g ++), takže to není zárukou, že chování více, než vzorku v původní otázce.

Nicméně, podle citace výše v prvním odstavci, standardní dělá skutečně zaručit.

#include <iostream>
class Foo {
    int x;
    public:
        Foo(): x(7) {
            std::cout << x << std::endl;
        }
};
int main (void) {
    Foo foo;
    return 0;
}
Odpovězeno 07/04/2009 v 03:30
zdroj uživatelem

hlasů
7

Jak již bylo odpověděl, seznamy inicializace získat zcela proveden před vstupem do konstruktoru blok. Takže je zcela bezpečné používat (nastala) členů v konstruktoru těle.

Provedli jste komentáře v přijaté odpovědi asi museli odkazovat na argumenty konstruktoru, nikoliv však člen vars uvnitř konstruktoru bloku. Vy ne.

Je možné, že jste si spletl, že byste měli odkazovat na parametry, a nikoli k atributům členských uvnitř seznamu inicializace. Jako příklad, vzhledem k tomu, třídní X, která má dva členy (a_ a b_) typu int, následující konstruktér může být špatně definované:

 X::X( int a ) : a_( a ), b( a_*2 ) {}

Možným problémem je, že výstavba prvků v seznamu inicializace závisí na pořadí prohlášení ve třídě a není pořadí, ve kterém je nutné zadat seznam inicializace. V případě, že třída byly definovány jako:

class X
{
public:
   X( int a );
private:
   int b_;
   int a_; 
};

Potom, bez ohledu na to, jak píšete seznam inicializace, faktem je, že b_ (a_ * 2) bude proveden před a_ se inicializuje protože prohlášení členů je první b_ a později a_. Že vytvoří chybu, jako váš kód je přesvědčen (a pravděpodobně závisí) na b_ dvojnásobné hodnoty A_, a ve skutečnosti b_ obsahuje odpadky. Nejjednodušším řešením není s odkazem na členy:

 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared

Vyhnout se tato úskalí je důvod, proč jste navrhl nepoužívat členem atributy jako součást inicializace ostatních členů.

Odpovězeno 07/04/2009 v 07:05
zdroj uživatelem

hlasů
7

Ano, C ++ konstruuje všechny členy před voláním constructur kód.

Odpovězeno 07/04/2009 v 03:31
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more