2014-11-29 10 views
13

Gdy próbuję skompilować this codeczłonkiem Konst stosu vs sterty

struct A { 
    const int j; 
}; 
A a; 

Wezmę oczekiwany błąd:

error: uninitialized const member in ‘struct A’

ale gdy próbuję skompilować this one:

struct A { 
    const int j; 
}; 
A * a = new A(); 

Zdobędę udaną kompilację.

Pytanie brzmi: dlaczego alokacja new pozwala na tworzenie zmiennych z członem const bez jawnego konstruktora i alokacji stosów - czy nie?

+1

Nie kompiluje się z GCC 4.9 lub Clang. http: //coliru.stacked-crooked.com/a/fadd1a456bfd5b82 –

+0

@remyabel Co oczywiście nie mówi nic o poprawności tego kodu. –

Odpowiedz

10

Nie jest to spowodowane przydziałem sterty, ale z powodu nawiasu używanego podczas przydzielania. Jeśli wykonasz np.

A* a = new A; 

to również się nie powiedzie.

Powodem, dla którego działa po dodaniu nawiasu, jest to, że struktura jest zainicjowana wartością, a dla typu POD takiego jak A wartość inicjalizująca wartość-inicjuje każdy element, a domyślna inicjalizacja wartości dla int wynosi zero.

Oznacza to, że będzie to prawdopodobnie działają tworzenia zmiennej na stosie, a także, jeśli po prostu dodać nawias wartości inicjalizacji:

A a = A(); // watch out for the http://en.wikipedia.org/wiki/Most_vexing_parse 

Mimo że przynosi inne potencjalne problemy, lepiej użyć jednolitego inicjalizacji, jeśli potrafisz (wymaga C++ 11):

A a{}; 
+6

'A();' będzie oczywiście * nigdy * działać. –

+1

Tak, przyjęto by to jako deklarację funkcji. – ravi

+0

'A a = A();' działałoby, ale czy 'A a {};' naprawdę działa? – juanchopanza

6

To jest źle sformułowane jak w C++ 14. §12.1 [class.ctor] stwierdza, że ​​

4 A defaulted default constructor for class X is defined as deleted if:

  • [...]
  • any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer does not have a user-provided default constructor,
  • [...]

A default constructor is trivial if it is not user-provided and if:

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • no non-static data member of its class has a brace-or-equal-initializer, and
  • all the direct base classes of its class have trivial default constructors, and
  • for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

§8.5 [dcl.init] mówi z kolei, że

7 To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);
  • [...]

8 To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • [...]

Pusta nawiasach powoduje wartości inicjalizacji. Domyślny konstruktor dla A jest zdefiniowany jako usunięty na [class.ctor]/p4. Tak więc, przez [dcl.init]/p8, inicjalizacja wartości oznacza domyślną inicjalizację, a przez p7 inicjalizacja jest źle sformułowana, ponieważ konstruktor został usunięty.

Wersja C++ 11 rzeczywiście dopuszczała inicjowanie wartości w tym kontekście; mówi o wartości inicjalizacji, która, między innymi,

if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

Ponieważ według powyższej definicji domyślnego konstruktora jest trywialny (chociaż jest usunięty), nie jest faktycznie nazwie. Zostało to uznane za wadę normy, a odpowiednie sformułowanie zostało zmienione przez CWG issue 1301.

Dostawcy kompilatorów zwykle wdrażają uchwały dotyczące wad, więc można to uznać za błąd w GCC 4.8, który został naprawiony w wersji 4.9.

Powiązane problemy