Die Initialisierung in C ++ ist wirklich verrückt. Beginnen Sie besser mit C.

Kürzlich wurde ich daran erinnert, warum ich es für eine schlechte Idee halte , Anfängern C ++ zu geben. Dies ist eine schlechte Idee , da in C ++ ein echtes Durcheinander ein schönes, aber perverses, tragisches und erstaunliches Durcheinander ist. Trotz des aktuellen Standes der Community richtet sich dieser Artikel nicht gegen modernes C ++. Vielmehr setzt sie den Artikel von Simon Brand teilweise fort: „Initialisierung in C ++ ist verrückt“, und teilweise ist es eine Botschaft an jeden Schüler, der seine Ausbildung beginnen möchte, um in den Abgrund zu schauen.

Typische Einwände der Schüler, wenn ihnen gesagt wird, dass sie C lernen sollen:

  • "Benutzt es jemand anderes?"
  • "Das ist dumm."
  • "Warum lernen wir C?"
  • "Wir müssen etwas besseres lernen, zum Beispiel C ++" ( Gelächter )

Es scheint, dass viele Schüler denken, dass das Lernen von C nicht wirklich wichtig ist (vom Autor: es ist nicht so) und stattdessen mit C ++ beginnen sollten. Schauen wir uns nur einen der Gründe an, warum dies eine absurde Aussage ist: eine verdammte Variable zu erstellen . Im ursprünglichen Artikel schlug Simon Brand vor, dass der Leser bereits mit den Kuriositäten der Initialisierung in Versionen vor C ++ 11 vertraut war. Hier schauen wir uns einige an und gehen etwas weiter.

Lassen Sie mich zunächst klarstellen, dass in diesem Artikel meine persönliche Meinung und nicht die offizielle Position der Universität Drexel, an der ich am Institut für Elektrotechnik und Informationstechnik unterrichte. Meine Vorlesungen sind in der Regel eher im Rahmen eines Ingenieurprogramms als in der Informatik enthalten, dh sie beziehen sich eher auf Systemprogrammierung und eingebettete Systeme.

Zusammenfassung in einem GIF


u / AlexAlabuzhev auf Reddit hat es geschafft, diesen gesamten Artikel in einem GIF zu wiederholen . (Ich denke, das ist das Originalwerk von Timur Dumler )


Ich habe nichts gegen C ++, aber es gibt eine Menge von allem, was Sie nicht in einem frühen Stadium benötigen.

Das ist alles. Geh nach Hause. Machen Sie einen Spaziergang mit dem Hund. Waschen Sie die Wäsche. Rufen Sie Mama an und sagen Sie, dass Sie sie lieben. Probieren Sie ein neues Rezept aus. Hier gibt es nichts zu lesen, Leute. Denken Sie in der Tat darüber nach, wie schlecht die Ingenieure (das heißt ich) in der Lage sind, ihre Gedanken zu vermitteln ...

Alles, überredete ich, so gut ich konnte!

Also, bist du noch hier? Echter Soldat. Wenn ich könnte, würde ich dir eine Medaille geben! Und leckere Schokoladenmilch!

Nun zurück zu unserer üblichen ... Programmierung.

Initialisierung in C.


Eintrag


Betrachten Sie zunächst die Initialisierung in C, da diese aus Kompatibilitätsgründen C ++ ähnelt. Es wird ziemlich schnell gehen, weil C so langweilig und einfach ist ( ähm ). Jeder Anfänger lernt diese Initialisierung auswendig, da sie in C anders funktioniert als in vielen neuen statisch typisierten Sprachen. Es gibt entweder eine Standardinitialisierung für akzeptable Werte oder es wird ein Kompilierungsfehler ausgegeben.

int main() {
    int i;
    printf("%d", i);
}

C , i ( i ). , , int i = 0;, . , , , , , , 0.

, .

int i;

int main() {
    printf("%d", i);
}

, ? i — .

.

, . , ? . , .

, .

struct A {
    int i;
};

int main() {
    struct A a;
    printf("%d", a.i);
}

. a . .

$ gcc -Wuninitalized a.c
a.c: In function ‘main’:
a.c:9:5: warning: ‘a.i’ is used uninitialized in this function [-Wuninitialized]
     printf("%d\n", a.i);

C . : 1)  , 2)  3)  .

struct A {
    int i;
} const default_A = {0};

void init_A(struct A *ptr) {
    ptr->i = 0;
}

int main() {
    /* helper function */
    struct A a1;
    init_A(&a1);

    /* during definition;
     * Initialize each member, in order. 
     * Any other uninitialized members are implicitly
     * initialized as if they had static storage duration. */
    struct A a2 = {0};

    /* Error! (Well, technically) Initializer lists are 'non-empty' */
    /* struct A a3 = {}; */

    /* ...or use designated initializers if C99 or later */
    struct A a4 = {.i = 0};

    /* default value */
    struct A a5 = default_A;
}

, C, , . , , 0.

C++


1.


C++, . , C , . C++, , , … … C++ C. :

struct A {
    int i;
};

int main() {
    A a;
    std::cout << a.i << std::endl;
}

C++ . C A, . C++ a , . A , , . « », :

struct A {
    A(){}
    int i;
}

, . g++ 8.2.1 , clang++ 7.0.1 ( -Wuninitialized). , .

$ g++ -Wuninitalized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:9:20: warning: ‘a.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a.i << std::endl;

C. A::i?

2.


, , ? , C++ , ? ()

struct A {
    int i;
};

int main() {
    A a = {.i = 0};
    std::cout << a.i << std::endl;
}

$ g++ -Wuninitialized -O2 -pedantic-errors a.cpp
a.cpp: In function ‘int main()’:
a.cpp:9:12: error: C++ designated initializers only available with -std=c++2a or -std=gnu++2a [-Wpedantic]
     A a = {.i = 0};

. C++ C++20. C++, 2020 . , C++ 21 , C. , -pedantic-errors gcc.

?

struct A {
    int i;
};

int main() {
    A a = {0};
    std::cout << a.i << std::endl;
}

$ g++ -Wuninitialized -O2 -pedantic-errors a.cpp
$

. A a = {}; , a.i. A . ?

C++11 ( ) C, , C. , , , . . ?

  1. .
  2. «».

, ? , . , A, . , int i, .

! - : ! .

C++11 … .

? , C++ . . . , , . . , , , .

3.


, C++ ( )! i :

struct A {
    A() : i(0) {}
    int i;
};

i .  — :

struct A {
    A() { i = 0; }
    int i;
};

, ( ).

C++11 (, ).

struct A {
    int i = 0; // default member initializer, available in C++11 and later
};

, , i 0, A . , A i, . :

struct A {
    A(int i = 0) : i(i) {}
    int i;
};

int main() {
    A a1;
    A a2(1);

    std::cout << a1.i << " " << a2.i << std::endl;
}

$ g++ -pedantic-errors -Wuninitialized -O2 a.cpp
$ ./a.out
0 1

. A a(); , a, A. ? - - , .

! . . C++, . !

4.


. , C++, . g++ (8.2.1), gnu++1y, C++14 GNU. , g++ C++17. « ?» — . , .

, C++11, , . , ? . : . . FAQ:

C++11 , .

({thing1, thing2, ...}, braced-init-list) :

#include <iostream> 
struct A {
    int i;
};
int main() {
    A a1;      // default initialization -- as before
    A a2{};    // direct-list-initialization with empty list
    A a3 = {}; // copy-list-initialization with empty list
    std::cout << a1.i << " " << a2.i << " " << a3.i << std::endl;
}

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:9:26: warning: ‘a1.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a1.i << " " << a2.i << " " << a3.i « std::endl;

, , ? a1.i. , , .

A a{}; , A a = {};. a braced-init-list. , A a = {};  — copy-list-initialization (). , A a; .

7/8 (, C++11):

  1. A .
  2. , A .
  3. , .
    1. int i{} i, 0.

?

int main() {
    A a1{0}; 
    A a2{{}};
    A a3{a1};
    std::cout << a1.i << " " << a2.i << " " << a3.i << std::endl;
}

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
$

a1.i 0, a2.i , a3 — , a1. , , ? , rvalue, , pr-, x-, gl-… , .

, C++11 , C++17 C++20 . , C++, - . . , C++17, . !

? ? ? , , ?

5. ,


, A ?

, :


  • //,
    • /


    • ( C++11, )
    • ( C++17)
    • (using Base::Base;, C++17)

:

#include <iostream>
struct A {
    A(){};
    int i;
};
int main() {
    A a{};
    std::cout << a.i << std::endl;
}

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:8:20: warning: ‘a.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a.i << std::endl;

A , .

7 :

  1. A .
  2. - braced-init-list , .
  3. , , , a.i .

, ?

struct A {
    A() = default;
};

, . , A .

struct A {
    A();
};
A::A() = default;

, . A(){} , .

? C++20 : , :). ? ! .

:

#include <iostream>
class A {
    int i;
    friend int main();
};
int main() {
    A a{};
    std::cout << a.i << std::endl;
}

A — , , i , main . . . , a.i , ?

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
$

. , . , a.i 0, :

  1. A, 2.
  2. , , braced-init-list , 3.
  3. , , 4.
  4. , ( ).

:

#include <iostream>
class A {
    int i;
    friend int main();
};
int main() {
    A a = {1};
    std::cout << a.i << std::endl;
}

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:7:13: error: could not convert ‘{1}’ from ‘<brace-enclosed initializer list>’ to ‘A’
     A a = {1};

A , :

  1. A, 2.
  2. .
  3. 1 A, .

:

#include <iostream>
struct A {
    A(int i) : i(i) {}
    A() = default;
    int i;
};
int main() {
    A a{};
    std::cout << a.i << std::endl;
}

, , , : , A . , ?

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
$

! :

  1. A, 2.
  2. , , braced-init-list , 3.
  3. ( ), , 4.
  4. , ( ).

:

#include <iostream>
struct A {
    A(){}
    int i;
};
struct B : public A {
    int j;
};
int main() {
    B b = {};
    std::cout << b.i << " " << b.j << std::endl;
}

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:11:25: warning: ‘b.B::<anonymous>.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << b.i << " " << b.j << std::endl;

b.j , b.i . ? ! b . Stack Overflow, , , . . , clang ( ) . .

...( ) ( ) , !

6.


C++11 std::initializer_list. : , std::initializer_list<T>. braced-init-list. , braced-init-list . initializer_list braced-init-list! , , . , ! , ?

struct A {
    template <typename T>
    A(std::initializer_list<T>) {}
    int i;
};

int main() {
    A a1{0};
    A a2{1, 2, 3};
    A a3{"hey", "thanks", "for", "reading!"};
    std::cout << a1.i << a2.i << a3.i << std::endl;
}

$ g++ -std=c++17 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:12:21: warning: ‘a1.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a1.i << a2.i << a3.i << std::endl;
                     ^
a.cpp:12:29: warning: ‘a2.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a1.i << a2.i << a3.i << std::endl;
                             ^
a.cpp:12:37: warning: ‘a3.A::i’ is used uninitialized in this function [-Wuninitialized]
     std::cout << a1.i << a2.i << a3.i << std::endl;

. A , std::initializer_list<T>. , , , i . T , .

  • , {0} std::initializer_list<int> 0.
  • {1, 2, 3} std::initializer_list<int> .
  • braced-init-list std::initializer_list<const char*> .

: A a{} , . , a{std::initializer_list<int> {}}. , A(std::initializer_list<int>){}.

std::initializer_list STL, : size, begin end. begin end , . , :

#include <vector>
#include <string>
int main() {
    std::vector<int> v_1_int{5};
    std::vector<int> v_5_ints(5);
    std::vector<std::string> v_strs = {"neato!", "blammo!", "whammo!", "egh"};
}

std::vector<T> , std::initializer_list<T>, , .

. v_1_int , std::initializer_list<int< init 5.

v_5_ints size_t count, (5) ( 0).

–, :

#include <iostream>
struct A {
    A(std::initializer_list<int> l) : i(2) {}
    A(int i = 1) : i(i) {}
    int i;
};
int main() {
    A a1;
    A a2{};
    A a3(3);
    A a4 = {5};
    A a5{4, 3, 2};
    std::cout << a1.i << " "
              << a2.i << " "
              << a3.i << " "
              << a4.i << " "
              << a5.i << std::endl;
}

, . : std::initializer_list<int>, int. , , i.

...? , .

$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
$ ./a.out
1 1 3 2 2

a1 . , , . a2 . A ( ), . A , . a3 , braced-init-list, 3 , int. , 4 , , std::initializer_list. , a5 - int, , a4.


, , ( ) , , . , , . ++, . ,  — . , . , . , -, , , .

, , C++ , ( ). . . , 5 . 18 .

C++. , , . C++, C++, , . C C , this C.

C — , , , . 18 .



, , . .



:

  1. Lobste.rs
  2. Hacker News
  3. Reddit

: , . ,  — . , C++. . , STL C, , . C , , C, , , , , . , C, , . C++, C++. C++ C++, C. , C++. .

, .

Source: https://habr.com/ru/post/de438492/


All Articles