12
votes

Est-ce un moyen sûr de mettre en œuvre un opérateur générique == et opérateur

Après avoir vu Cette question , ma première pensée était que ce serait trivial pour définir l'équivalence générique et les opérateurs relationnels: xxx

à l'aide de namepace std :: rel.oops serait alors encore plus utile, car il serait fait Entièrement générique par les implémentations par défaut des opérateurs == et << / code>. Évidemment, cela n'effectue pas une comparaison de MADWise, mais plutôt un peu, comme si le type ne contient que des membres de la POD. Ceci n'est pas entièrement cohérent avec la manière dont C ++ génère des constructeurs de copies, par exemple, que faire effectuer des copies par incorpores.

Mais je me demande si la mise en œuvre ci-dessus est bien en sécurité. Les structures auraient naturellement le même emballage, étant du même type, mais le contenu du rembourrage garantirait-il être identique (par exemple, rempli de zéros)? Y a-t-il des raisons pour lesquelles ou des situations dans lesquelles cela ne fonctionnerait pas?


7 commentaires

Pourquoi voudriez-vous faire cela? Sans cela, vous obtiendrez une belle erreur de compilation pratique si vous n'avez pas d'égalité ou moins que l'opérateur. Avec cela, l'erreur de compilée est partie et vous avez silencieusement ce qui est probablement les mauvais opérateurs. Vous créez soigneusement des bugs de manière à ce qu'ils ne soient pas facilement vus.


RXWEN.Blogspot.com/2009/12/Utilise- memcmp-to-comparer-objets.htm l


@David: Je ne l'utiliserais presque certainement pas dans le code réel, mais il ne peut pas nuire à spéculer.


À l'envers, je pense que c'est un excellent moyen de se venger de votre entreprise si vous venez de vous faire viré. Jamais mieux que #define null rand ()% 1000? 0: 1


@DumbCoder: C'est fondamentalement la réponse que je cherchais. Postez-le et je vais accepter.


@Viktor. TTT ... TTT. Quand les gens vont-ils apprendre? #define null (rand ()% 1000? 0: 1) . Parenthentez toujours des macros, en particulier lorsqu'ils utilisent des opérateurs de manière basse sur la table de prime. Votre chemin pourrait probablement causer des erreurs compilées.


@Jon Purdy: C'est une raison assez juste, mais après quelques années dans le domaine des gens posant des questions comme ça donnez-moi un sentiment mal à l'aise. Heureux de savoir que c'est une curiosité inutile.


6 Réponses :


2
votes

C'est très dangereux car le compilateur utilisera ces définitions non seulement pour les anciennes structures simples, mais également pour toutes classes, aussi complexes, pour lesquelles vous avez oublié de définir == et << / code> correctement.

Un jour, il vous mordra.


1 commentaires

Vous pouvez dire exactement la même chose à propos des constructeurs de copie par défaut et des opérateurs d'affectation. Quelle est la dangerosité d'un point de vue de conception n'est pas vraiment ma question. Quelle est la dangerosité d'un point de vue indéfini / non spécifié / non spécifié et défini par la mise en œuvre est.



0
votes

Beaucoup peut dépendre de votre définition d'équivalence.

E.g. Si l'un des membres que vous comparez au sein de vos classes est des chiffres de points flottants.

La mise en œuvre ci-dessus peut traiter deux doubles, car elles ne sont pas égales, même s'ils venaient du même calcul mathématique avec les mêmes entrées - car ils n'ont peut-être pas généré exactement la même sortie - plutôt deux nombres très similaires.

Typiquement, ces chiffres doivent être comparés numériquement avec une tolérance appropriée.


0 commentaires

3
votes

Même pour POD, == Opérateur peut être faux. Cela est dû à l'alignement des structures comme le suivant qui prend 8 octets sur mon compilateur.

class Foo {
  char foo; /// three bytes between foo and bar
  int bar;
};


0 commentaires

13
votes

Non - juste par exemple, si vous avez t == (flotteur | double | Long Double), votre opérateur == ne fonctionne pas correctement. Deux nans ne devraient jamais comparer comme étant égales, même si elles ont le modèle de bits identique (en fait, une méthode courante de détection d'un Nan est de comparer le nombre à lui-même - s'il n'est pas égal à lui-même, c'est une Nan). De même, deux nombres de points flottants avec tous les bits dans leurs exposants réglés sur 0 ont la valeur 0.0 (exactement), quels que soient les bits pourraient être définis / clairs dans le signaland.

Votre << / code> a encore moins de chances de travailler correctement. Par exemple, envisagez une implémentation typique de std :: string qui ressemble à ceci: xxx

avec cette commande des membres, votre Opérateur << / Code> fera sa comparaison en fonction des adresses des tampons où les chaînes ont enregistré leurs données. Si, par exemple, cela aurait été écrit avec le membre d'abord, votre comparaison utiliserait les longueurs des chaînes comme touches principales. En tout cas, il ne sera pas une comparaison basée sur le contenu de la chaîne réelle, car il ne considérera jamais la valeur du pointeur Data , pas ce que cela pointe A, qui est ce que vous voulez vraiment / besoin.

EDIT: En ce qui concerne le remplissage, il n'y a aucune obligation que le contenu du rembourrage soit égal. Il est également théoriquement possible que le rembourrage soit une sorte de représentation du piège qui provoquera un signal, lancer une exception ou quelque chose sur cet ordre, si vous essayez même de le regarder du tout. Pour éviter de telles représentations de pièges, vous devez utiliser quelque chose comme une distribution pour l'examiner en tant que tampon de non signé Char s. memcmp peut faire cela, mais à nouveau, il pourrait ne pas ...

Notez également que être les mêmes types d'objets les pas signifient nécessairement l'utilisation le même alignement des membres. C'est une méthode de mise en œuvre courante, mais elle est également entièrement possible pour un compilateur de faire quelque chose comme à utiliser différents alignements basés sur la fréquence à laquelle il "pense" un objet particulier sera utilisé et inclure une étiquette d'une sorte dans l'objet (par exemple, une valeur écrite dans le premier octet de rembourrage) qui indique l'alignement de cette instance particulière. De même, il pourrait séparer les objets par (par exemple) l'adresse (par exemple), un objet situé à une adresse même contient une alignement de 2 octets, à une adresse qui est un multiple de quatre a une alignement de 4 octets, etc. (cela ne peut pas être Utilisé pour les types de pod, mais sinon, tous les paris sont éteints).

aucun de ceux-ci n'est probable ou courant, mais je ne peux penser à rien dans la norme qui les interdisent non plus.


4 commentaires

Je suis parfaitement conscient que cela ne fonctionne probablement pas correctement pour la plupart des situations. Ce que je demande, c'est que cela invoque un comportement non défini, non spécifié ou défini par la mise en œuvre pour effectuer une comparaison des structures (éventuellement incorrecte) selon laquelle ils sont POD.


À quel point êtes-vous sûr que des instances individuelles d'un type peuvent avoir des exigences d'alignement uniques? À tout le moins, cela affecterait la taille de l'objet, ce qui n'est pas autorisé. Je peux voir où cela pourrait être possible, cela ne semble tout simplement pas jadir avec ma compréhension des règles d'alignement.


@Dennis: Eh bien, je suis à peu près sûr qu'il n'y a rien dans la norme pour le permettre spécifiquement, mais je ne peux penser à rien qui l'interdirait non plus. La seule fois où il semble que cela puisse être utile serait quand il a été utilisé comme classe de base, qui dépose des règles sur la taille de (base_subobject). Changer l'alignement ne change pas nécessairement la taille non plus - cela change simplement lorsque vous placez le rembourrage (à la fin d'une structure contre des membres) - bien qu'il élimine la majeure partie de la motivation pour le faire.


Ouais, plus j'y pense, plus je suis convaincu que je suis qu'il y a quelque chose qui l'interdite. Il serait simplement si terriblement gênant de mettre en œuvre, je ne peux pas imaginer que cela soit effectivement bénéfique, sauf peut-être comme une classe de base.



0
votes

Toute structure ou classe contenant un seul pointeur échouera instantanément une sorte de comparaison significative. Ces opérateurs ne travailleront que pour une classe qui constitue des données anciennes simples, ou une pod. Un autre répondeur a correctement souligné des points flottants en tant que cas où même cela ne tiendra pas vrai et que les octets de rembourrage.

Réponse courte: Si c'était une idée intelligente, la langue en serait similaire à celle des constructeurs de copie / des opérateurs d'affectation par défaut.


0 commentaires

6
votes

Ne faites jamais cela sauf si vous êtes sûr à 100% sur la mise en page de la mémoire, le comportement du compilateur, et que vous ne vous souciez vraiment pas de la portabilité, et vous voulez vraiment gagner l'efficacité

Source


0 commentaires