C ++ a trois façons de passer des paramètres à une fonction: par valeur, par référence lvalue et par référence rvalue. Parmi ceux-ci, le passage par la valeur crée la propriété dans le sens où la fonction appelée reçoit sa propre copie, et le passage par la référence rvalue indique que la valeur peut être consommée, c'est-à-dire qu'elle ne sera plus utilisée par l'appelant. Le passage par la référence lvalue signifie que l'objet est temporairement emprunté à l'appelant.
Cependant, ceux-ci ont tendance à être «par convention» et ne peuvent pas toujours être vérifiés par le compilateur. Et vous pouvez accidentellement transformer une référence lvalue en une référence rvalue à l'aide de std::move()
. Concrètement, il y a trois problèmes:
Une référence peut survivre à l'objet auquel elle fait référence. Le système à vie de Rust empêche cela.
Il peut y avoir plus d'une référence mutable / non const active à tout moment. Le vérificateur d'emprunt de Rust empêche cela.
Vous ne pouvez pas refuser les références. Vous ne pouvez pas voir sur un site d'appel si cette fonction crée une référence à votre objet, sans connaître la signature de la fonction appelée. Par conséquent, vous ne pouvez pas empêcher de manière fiable les références, ni en supprimant les méthodes spéciales de vos classes ni en vérifiant le site d'appel pour vérifier la conformité avec certains guides de style «sans références».
Le problème de durée de vie concerne la sécurité de base de la mémoire. Il est bien sûr illégal d'utiliser une référence lorsque l'objet référencé a expiré. Mais il est très facile d'oublier la durée de vie lorsque vous stockez une référence dans un objet, en particulier lorsque cet objet dépasse la portée actuelle. Le système de type C ++ ne peut pas tenir compte de cela car il ne modélise pas du tout la durée de vie des objets.
Le std::weak_ptr
pointeur intelligent code la sémantique de propriété similaire à une simple référence, mais nécessite que l'objet référencé soit géré via un shared_ptr
, c'est-à-dire qu'il soit compté par référence. Ce n'est pas une abstraction à coût nul.
Alors que C ++ a un système const, cela ne suit pas si un objet peut être modifié, mais suit si un objet peut être modifié via cette référence particulière . Cela ne fournit pas de garanties suffisantes pour une «concurrence courageuse». En revanche, Rust garantit que s'il y a une référence mutable active qui est la seule référence ("Je suis le seul qui peut changer cet objet") et s'il y a des références non mutables alors toutes les références à l'objet sont non mutables ("Alors que je peux lire à partir de l'objet, personne ne peut le changer").
En C ++, vous pourriez être tenté de protéger l'accès à un objet via un pointeur intelligent avec un mutex. Mais comme discuté ci-dessus, une fois que nous avons une référence, il peut échapper à sa durée de vie attendue. Un tel pointeur intelligent ne peut donc pas garantir qu'il s'agit du point d'accès unique à son objet géré. Un tel schéma peut en fait fonctionner dans la pratique parce que la plupart des programmeurs ne veulent pas se saboter, mais d'un point de vue système de type, cela est encore complètement malsain.
Le problème général avec les pointeurs intelligents est qu'ils sont des bibliothèques en plus du langage principal. L'ensemble des fonctionnalités du langage de base permet à ces pointeurs intelligents, par exemple std::unique_ptr
besoin de constructeurs de mouvement. Mais ils ne peuvent pas corriger les lacunes du langage principal. Les capacités de créer implicitement des références lors de l'appel d'une fonction et d'avoir des références pendantes signifient que le langage C ++ de base n'est pas sain. L'incapacité de limiter les références mutables à une seule signifie que C ++ ne peut garantir la sécurité contre les conditions de concurrence avec tout type de concurrence.
Bien sûr, à bien des égards, C ++ et Rust se ressemblent plus qu'ils ne se ressemblent, en particulier en ce qui concerne leurs concepts de durée de vie d'objets statiquement déterminées. Mais bien qu'il soit possible d'écrire des programmes C ++ corrects (à condition qu'aucun des programmeurs ne fasse d'erreur), Rust garantit l' exactitude des propriétés discutées.