NotANameServer / discord

Règles et gestion du serveur Discord de programmation Not a Name : https://discord.gg/zcWp9sC
23 stars 10 forks source link

C++ TL;DR news 3 #30

Closed GuillaumeBelz closed 3 years ago

GuillaumeBelz commented 3 years ago

Cf l'issue precedente pour les idees d'articles https://github.com/NotANameServer/discord/issues/26

A publier le 30 mai

GuillaumeBelz commented 3 years ago

The Subtle Dangers of Temporaries in for Loops

Lire l’article : https://www.fluentcpp.com/2021/05/22/the-subtle-dangers-of-temporaries-in-for-loops/

Le site est down

GuillaumeBelz commented 3 years ago
GuillaumeBelz commented 3 years ago

A list of bad practices commonly seen in industrial projects

Lire l’article : https://belaycpp.com/2021/06/01/a-list-of-bad-practices-commonly-seen-in-industrial-projects/

Voici un article qui se lit facilement, sur les mauvaises pratiques que l'on rencontre régulièrement dans des projets industriels. Il n'y a rien de nouveau, mais c'est bien de faire des rappels de temps en temps.

Si tu veux en savoir plus sur la qualité du code, je te conseille les livres de C. Martin (Clean code, Clean coder, Clean architecture).

GuillaumeBelz commented 3 years ago

GotW #102 Solution: Assertions and “UB” (Difficulty: 7/10)

Lire l’article : https://herbsutter.com/2021/06/03/gotw-102-solution-assertions-and-ub-difficulty-7-10/

Herb Sutter est l'un des experts C++ les plus influents : membre du comité de normalisation du C++, auteur de plusieurs livres très connus, speaker dans plusieurs conférences (je te conseille ses talks à la CppCon), développeur chez Microsoft.

Cet article est un Guru of the Week (GotW). Les GotW sont des articles de blog qu'il écrit depuis des dizaines d'années. Le principe est de poser une série de questions sur un thématique dans un premier article, les lecteurs apportent des éléments de réponse aux questions, puis un second article "GotW Solution" présente les explications.

Cette article est la solution du GotW 102 : https://herbsutter.com/2021/05/25/gotw-102-assertions-and-ub-difficulty-7-10/

Quelques définitions

Comportement indéfini (undefined behavior ou UB)

Est "ce qu'il se passe lorsque votre programme essaie de faire quelque chose dont le sens n'est pas du tout défini dans le langage ou la bibliothèque standard C++ (code et/ou données illégaux)". Le compilateur peut faire ce qu'il veut.

Comportement non spécifié (unspecified behavior)

Est "ce qu'il se passe lorsque votre programme fait quelque chose pour lequel la norme C++ ne documente pas les résultats". Le résultat est valide mais tu ne sais pas à l'avance ce qu'il sera.

Comportement défini par l'implémentation (Implementation-defined behavior)

Dépend du compilateur.

Codes d'exemple

Comportement indéfini

Exemple avec le déréférencement d'un pointeur null.

void deref_and_set( int* p ) {
    assert( p );
    *p = 42;
}

Comportement non spécifié

Exemple avec le calcul d'un point médian.

int midpoint( int low, int high ) {
    assert( low <= high );
    return low + (high-low)/2;
        // less overflow-prone than “(low+high)/2”
        // more accurate than “low/2 + high/2”
}

Guideline : un comportement non spécifié peut devenir un comportement indéfini si tu utilises le résultat sans vérifier que le résultat retourné ne produise pas un comportement indéfini.

Guideline : ne spécifie pas le comportement de ta fonction (postconditions) pour les entrée invalides (préconditions).

Comportement défini par l'implémentation

Dans le code d'exemple suivant, le comportement de la fonction ne devrait pas être valide si x est nul (assert). Mais un test est ajouté (programmation défensive) pour que le comportement soit quand même valide en release si l'utilisateur de la fonction fait une erreur.

some_result_value DoSomething( int x ) {
    assert( x != 0 );
    if ( x == 0 ) { return error_value; }
    return sensible_result(x);
}

Guideline : ne pas respecter une assertion n'est pas nécessairement un comportement indéfini.

Guideline : toujours documenter les contraintes sur les entrées de fonction (préconditions). L'utilisateur de la fonction doit savoir quelles valeurs d'entrée sont invalides.

Guideline : toujours respecter les préconditions quand tu utilises une fonction.

GuillaumeBelz commented 3 years ago

17 Smaller but Handy C++17 Features

Lire l’article : https://www.cppstories.com/2019/08/17smallercpp17features/

Le titre de cet article est explicite : il présente 17 fonctionnalités mineurs mais utiles du C++17. Quelques fonctionnalités concernent le langage, mais la grande majorité concerne la bibliothèque standard. Les fonctionnalités majeures (structured bindings, filesystem, parallel algorithms, if constexpr, std::optional, std::variant, etc.) ne sont pas abordées ici.

Pour le langage

L'allocation dynamique pour les données alignées, avec new

Par exemple pour les données SIMD. Dans le code suivant, en C++11/14, l'alignement n'est pas garantie. En C++17, l'alignement est garantie.

class alignas(16) vec4 
{
    float x, y, z, w;
};

auto pVectors = new vec4[1000];

Les variables membres statiques peuvent être inline en C++17

class MyClass {
    static inline std::string startName = "Hello World";
};

Ajout de la direction du pré-processeur __has_include

Pour vérifier si un header a déjà été inclus ou pas.

#if defined __has_include
#    if __has_include(<charconv>)
#        define has_charconv 1
#        include <charconv>
#    endif
#endif

Pour la bibliothèque standard

Ajout des variables template dans les traits

En C++14, le suffixe _t a été ajouté pour les traits pour remplacer ::type. En C++17, le suffixe _v est ajouté pour remplacer ::value.

std::is_integral_v<T>
std::is_class_v<T>

Ajout des méta-fonctions pour les opérateurs logiques.

#include<type_traits>

template<typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<int, Ts>...> >
PrintIntegers(Ts ... args) { 
    (std::cout << ... << args) << '\n';
}

Ajout de std::void_t

Ce type peut être utile dans certaines implémentation de méta-fonctions.

template< class... >
using void_t = void;

Ajout de conversion de chaînes std::from_chars

Bas niveau et rapide, mais nécessite un peu plus de code.

const std::string str { "12345678901234" };
int value = 0;
const auto res = std::from_chars(str.data(), str.data() + str.size(), value);

Extraire un noeud d'une map ou d'un set

Permet de simplifier et optimiser le déplacement des noeuds.

inSet.emplace("John");
auto handle = inSet.extract("John");
outSet.insert(std::move(handle));

Ajout de try_emplace() dans std::map et std::unordered_map

emplace prend les arguments, même si l'insertion échoue, alors que try_emplace ne fait rien en cas d'échec.

std::map<std::string, std::string> m;
m["Hello"] = "World";

m.emplace("Hello", std::move(s)); // échec de l'insertion
// s a été move après emplace

m.try_emplace("Hello", std::move(s)); // échec de l'insertion
// s n'a pas été move après try_emplace

Ajout de insert_or_assign() dans std::map et std::unordered_map

insert n'ajoute pas l'élément si la clé existe déjà, insert_or_assign ajoute l'élément dans tous les cas.

myMap.insert_or_assign("c", "cherry"); // map contient "cherry"
myMap.insert_or_assign("c", "clementine"); // map contient "clementine"

emplace retourne le nouvel élément ajouté

// since C++11 and until C++17 for std::vector
template< class... Args >
void emplace_back( Args&&... args );

// since C++17 for std::vector
template< class... Args >
reference emplace_back( Args&&... args );

Ajout d'un nouvel algorithme std::sample

Pour extraire aléatoirement n éléments.

Ajouts de plusieurs fonctions mathématiques.

Par exemple gcd(), lcm(), clamp(), etc.

Support des tableaux dans std::shared_ptr

Avant, c'était possible uniquement avec std::unique_ptr.

std::shared_ptr<int[]> ptr(new int[10]);

Ajout de std::scoped_lock

Pour lock plusieurs mutex en même temps.

std::scoped_lock lck(first_mutex, second_mutex);

Ajoute de std::invoke

Pour invoquer des fonctions.

// a regular function:
std::cout << std::invoke(foo, 10, 12) << '\n';

// a lambda:
std::cout << std::invoke([](double d) { return d*10.0;}, 4.2) << '\n';

Fonctionnalités supprimées

Suppression de std::auto_ptr

Enfin !

Suppression des anciens utilitaires pour les fonctions

unary_function(), binary_function(),ptr_fun()`, etc.

GuillaumeBelz commented 3 years ago

C++ vs Rust — simple polymorphism comparison

Lire l’article : https://itnext.io/c-vs-rust-simple-polymorphism-comparison-e4d16024b57

L'auteur de cet article compare comment le polymorphisme est implémenté en C++ et en Rust. Le propos du polymorphisme est de pouvoir accéder à un type concret, dérivé d'un type de base, à l'éxecution, via un pointeur ou une référence.

Par exemple, des classes Dog et Cat qui dérivent de Animal.

Le code d'exemple :

#include <iostream>
#include <memory>
#include <vector>

class Animal {
public:
    virtual ~Animal() = default;
    virtual void talk() const = 0;
};

class Dog final : public Animal {
public:
    void talk() const override { std::clog << "I'm a dog\n"; }
};

class Cat final : public Animal {
public:
    void talk() const override { std::clog << "I'm a cat\n"; }
};

int main() {
    std::vector<std::unique_ptr<Animal>> animals;
    animals.emplace_back(std::make_unique<Dog>());
    animals.emplace_back(std::make_unique<Cat>());
    for (const auto& animal: animals) {
        animal->talk();
    }
}

Affiche :

I'm a dog
I'm a cat

La version Rust :

trait Animal {
    fn talk(&self);
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn talk(&self) {
        println!("I'm a dog");
    }
}

impl Animal for Cat {
    fn talk(&self) {
        println!("I'm a cat");
    }
}

fn main() {
    let animals : Vec<Box<dyn Animal>> = vec![Box::new(Dog{}), Box::new(Cat{})];
    for animal in animals.iter() {
        animal.talk();
    }
}

Les différences entre les versions C++ et Rust :

GuillaumeBelz commented 3 years ago

Publié : https://zestedesavoir.com/billets/3961/c-tl-dr-news-3/