2015-06-26 7 views
6

Załóżmy, że masz klasę o nazwie produktu, zdefiniowane następująco:Kiedy można kompilować optymalizację inicjowania stylu auto + brace?

class Product 
    { 
    public: 
     Product(const char *name, int i); 
     Product(Product &&rhs); 
     Product(const Product &rhs); 
     ~Product(); 
    private: 
     const char *m_name; 
     int m_i; 
    }; 

i zainicjować zmienną tak:

auto p = Product{"abc",123}; 

Myślałem, że średnia podyktowane że kompilator musi logicznie wykonaj następujące czynności :

  • konstrukcją tymczasową produktu
  • ruch konstrukt P (przy użyciu tymczasowy produkt)

Ale kompilator mógł to zoptymalizować, aby p było konstruowane bezpośrednio.

I zweryfikowane to (Visual Studio 2013) i rzeczywiście, kompilator optymalizuje ten, nawet jeśli mamy własną niestandardową (inny niż domyślny) move-konstruktor. Jest okej.

Jednakże, jeśli jawnie usunąć i przenieść kopiowaniem-konstruktora, na przykład:

class Product 
    { 
    public: 
     Product(const char *name, int i); 
     Product(Product &&rhs) = delete; 
     Product(const Product &rhs) = delete; 
     ~Product(); 
    private: 
     const char *m_name; 
     int m_i; 
    }; 

auto + klamra inicjalizacji nadal kompiluje. Chociaż kompilator musiał temu zapobiec, ponieważ nie było dozwolonego kopiowania ani przenoszenia.

tyle dziwne, jeśli robię usuniętego przed kopiowaniem i przenieść-konstruktora prywatnych, jak poniżej:

class Product 
    { 
    public: 
     Product(const char *name, int i); 
     ~Product(); 
    private: 
     Product(Product &&rhs) = delete; 
     Product(const Product &rhs) = delete; 
     const char *m_name; 
     int m_i; 
    }; 

Następnie inicjalizacji auto + klamra nie kompilator już.

error C2248: 'Product::Product' : cannot access private member declared in class 'Product' 

Czy to oczekiwane zachowanie? Czy to błąd w Visual Studio 2013 (aktualizacja 3)?

Uwaga: Uwaga: Próbowałem skompilować to na ideone i tam rzeczywiście odmawia kompilacji inicjowania, gdy konstruktorzy kopiowania i przenoszenia są usuwane (i publiczne). Więc myślę, że to błąd Visual Studio.

+1

Wystarczy FYI w Visual Studio 2013, * kompilator generowane * konstruktorzy coraz szerzej operatory przypisania są obsługiwane ** ** nie (choć można definiować własne). [Tutaj znajduje się lista C++ 11 VS2013 (non)) (https://msdn.microsoft.com/en-us/library/hh567368.aspx#featurelist) – CoryKramer

+0

Wersja kompilatora 18.00.30723. Czy ten błąd można wprowadzić między 21005 a 30723? – Patrick

+0

@ Patricka NVM. Raz podałem puste nawiasy dla konstruktora i destruktora skompilowanego na VS. – NathanOliver

Odpowiedz

1

Standard jest bardzo przejrzysty, jak wspomniano wcześniej, co oznacza, że ​​jest to błąd w kompilatorze. Nigdy nie można być pewnym, chociaż jeśli jeden kompilator coś mówi, a wszyscy inni się nie zgadzają, spodziewam się, że będzie to jedna z wielu niezgodnych z normami implementacji kompilatora MSVC.

Interpretacja szczęk wersji 3.7 (syn-build)

t.cpp:19:7:{19:11-19:30}: error: call to deleted constructor of 'Product' 
     [Semantic Issue] 
     auto p = Product{"abc", 123}; 
      ^ ~~~~~~~~~~~~~~~~~~~ 
t.cpp:8:2: note: 'Product' has been explicitly marked deleted here 
     [Semantic Issue] 
     Product(Product &&rhs) = delete; 
     ^
1 error generated. 
make: *** [t.o] Error 1 

Interpretacja gcc 4.8:

t.cpp: In function ‘int main()’: 
t.cpp:19:29: error: use of deleted function ‘Product::Product(Product&&)’ 
    auto p = Product{"abc", 123}; 
          ^
t.cpp:8:2: error: declared here 
    Product(Product &&rhs) = delete; 
^
make: *** [build/gcc/t.o] Error 1 

Należy także pamiętać, że Explicitly Defaulted and Deleted Functions są nowe od MSVC 2013 oraz realizacja nie jest jeszcze zakończona. Jakby jeszcze nie zrozumiał = domyślny dla konstruktorów ruchu.

Domyślam się, że MSVC 2013 nie sprawdza konstruktora ruchu lub po prostu wraca do konstruktora kopiowania.

Interesujące może być sprawdzenie MSVC 2015, ponieważ wydaje się, że ma ono (bardziej) kompletną implementację tych konstrukcji.

JVApen

+1

Program Visual Studio 2015 rzeczywiście podaje błąd (Product :: Product (Product &&) ": próba odwołania się do usuniętej funkcji). To był wyraźnie błąd w Visual Studio 2013. – Patrick

0

W linii

auto p = Product{"abc",123}; 

znak równości nie jest oznaczający operator przypisania, ale jest po prostu składnia dla inicjatora. W związku z tym kompilator nie optymalizuje niczego, a jedynie wykonuje inicjalizację.

+0

Dlaczego to się nie udaje, gdy konstruktor przenoszenia i kopiowania zostanie usunięty I prywatny? – Patrick

+0

To nie jest poprawne. Zgodnie ze standardem kompilator musi najpierw skonstruować tymczasowy, a następnie przenieść - skonstruować go do zmiennej. Ale kompilator może to zoptymalizować (konstruując zmienną bezpośrednio), pod warunkiem, że efekt logiczny będzie taki sam, jak budowa + moveconstruction, co nie ma miejsca, jeśli usunięto obiekt moveconstructor. – Patrick

Powiązane problemy