Sérieusement, quoi de neuf. Il y a une conversion implicite de std::string
à std::string_view
et ce n'est pas considéré comme dangereux. Même si cela peut sûrement causer beaucoup de références pendantes si le programmeur ne fait pas attention.
En revanche, ils ont rejeté une conversion implicite de std::string_view
à std::string
utilisant le même argument mais de façon complètement opposée: car le programmeur peut ne pas faire attention .
C'est très agréable qu'ils aient créé un remplacement pour un _ const char*
pointeur tout en le rendant super déroutant et dénudé jusqu'à l'os:
const char*
-> std::string
: OK std::string_view
-> std::string
: NON std::string
= const char*
: OK std::string
= std::string_view
: OK std::string
+ = const char*
: OK std::string
+ = std::string_view
: OK const char*
+ std::string
: OK std::string_view
+ std::string
: NON std::string
+ const char*
: OK std::string
+ std::string_view
: NON Suis-je en train de manquer quelque chose ou est-ce une absurdité totale?
En fin de compte, quelle est l'utilité de cette vue de chaîne sans toutes les pièces cruciales qui la rendent similaire à const char*
? Quel est l'intérêt de l'intégrer dans l'écosystème de stdlib sans faire la dernière étape pour le compléter? Après tout, si nous avions juste besoin d'un objet qui représente un morceau de chaîne, nous pourrions écrire le nôtre. En fait, beaucoup de bibliothèques l'ont déjà fait, il y a des années. L'intérêt de faire quelque chose de standard est de le rendre utile pour la plus large gamme de cas d'utilisation, n'est-ce pas?
Vont-ils résoudre ce problème dans C++ 2a?
Le problème est que std::string_view
-> std::string
crée une copie de la mémoire sous-jacente, complète avec l'allocation de tas, tandis que l'implicite std::string
-> std::string_view
ne fait pas. Si vous avez pris la peine d'utiliser un std::string_view
en premier lieu, vous vous souciez évidemment des copies, vous ne voulez donc pas que cela se produise implicitement.
Considérez cet exemple:
void foo1(const std::string& x)
{
foo2(x);
}
void foo2(std::string_view x)
{
foo3(x);
}
void foo3(const std::string& x)
{
// Use x...
}
La fonction foo2
aurait pu utiliser un const std::string&
paramètre, mais utilisé un std::string_view
pour qu'il soit plus efficace si vous passez une chaîne qui n'est pas un std::string
; pas de surprise là-bas. Mais c'est moins efficace que si vous veniez de lui donner un const std::string&
paramètre!
foo2
est appelé avec un std::string
argument (par exemple par foo1
): Quand foo2
appels foo3
, il crée une copie de la chaîne. S'il avait un const std::string&
argument, il aurait pu utiliser l'objet qu'il avait déjà.foo2
est appelé avec un const char*
argument: A std::string
une copie doit être faite tôt ou tard; avec un const std::string&
paramètre, il est créé plus tôt, mais dans l'ensemble, il y a exactement une copie de toute façon.Imaginez maintenant foo2
appelle plusieurs fonctions comme foo3
, ou appelle foo3
en boucle; ça fait exactement la même chose std::string
objet encore et encore. Vous souhaitez que le compilateur vous en informe.