L'initialisation en C ++ est vraiment folle. Mieux vaut commencer par C

Récemment, on m'a rappelé pourquoi je considÚre que c'est une mauvaise idée de donner aux débutants du C ++. C'est une mauvaise idée , car en C ++, un vrai gùchis est un gùchis beau, mais perverti, tragique et étonnant. Malgré l'état actuel de la communauté, cet article n'est pas dirigé contre le C ++ moderne . Au lieu de cela, elle poursuit partiellement l' article de Simon Brand, «L'initialisation en C ++ est fou», et en partie c'est un message pour chaque étudiant qui veut commencer ses études en regardant dans l'abßme.

Objections typiques des étudiants lorsqu'ils apprennent l'apprentissage de C:

  • "Est-ce que quelqu'un d'autre l'utilise?"
  • "C'est stupide."
  • "Pourquoi apprenons-nous le C?"
  • «Nous devons apprendre quelque chose de mieux, par exemple le C ++» ( rires )

Il semble que de nombreux étudiants pensent que l'apprentissage du C n'a pas vraiment d'importance (de l'auteur: ce n'est pas le cas) et devraient plutÎt commencer par le C ++. Examinons une des raisons pour lesquelles il s'agit d'une proposition absurde: créer une putain de variable . Dans l'article d'origine, Simon Brand a suggéré que le lecteur connaissait déjà les bizarreries de l'initialisation dans les versions antérieures à C ++ 11. Ici, nous regardons certains d'entre eux et allons un peu plus loin.

Permettez-moi de commencer par expliquer que dans cet article mon opinion personnelle, et non la position officielle de l'UniversitĂ© de Drexel, oĂč j'enseigne au DĂ©partement de gĂ©nie Ă©lectrique et informatique. Mes cours sont gĂ©nĂ©ralement inclus dans le cadre d'un programme d'ingĂ©nierie, plutĂŽt qu'en informatique, c'est-Ă -dire qu'ils concernent davantage la programmation systĂšme et les systĂšmes embarquĂ©s.

Résumé dans un GIF


u / AlexAlabuzhev sur Reddit a rĂ©ussi Ă  relire cet article en entier dans un gif. (Je pense que c'est l'Ɠuvre originale de Timur Dumler )


Je n'ai rien contre C ++, mais il y a beaucoup de tout ce dont vous n'avez pas besoin à un stade précoce.

C’est tout. Rentre chez toi. Faites une promenade avec le chien. Lavez le linge. Appelez maman et dites que vous l'aimez. Essayez une nouvelle recette. Rien Ă  lire ici les gars. En fait, pensez Ă  quel point les ingĂ©nieurs (c'est-Ă -dire moi) sont incapables de transmettre leurs pensĂ©es ...

Tout, j'ai persuadé comme je le pouvais!

Alors, tu es toujours là? Vrai soldat. Si je pouvais, je te donnerais une médaille! Et un délicieux lait au chocolat!

Revenons maintenant Ă  notre ... programmation habituelle.

Initialisation en C


Entrée


Tout d'abord, envisagez l' initialisation en C car elle est similaire Ă  C ++ pour des raisons de compatibilitĂ©. Ce sera assez rapide, car C est tellement ennuyeux et simple ( ahem ). Chaque dĂ©butant apprend cette initialisation par cƓur, car en C, cela fonctionne diffĂ©remment que dans de nombreux nouveaux langages typĂ©s statiquement. Il existe soit une initialisation par dĂ©faut pour les valeurs acceptables, soit une erreur de compilation est levĂ©e.

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/fr438492/


All Articles