7
votes

Je veux allouer un objet sur la pile avec C #

dire que j'ai cette classe C #: xxx

Comment puis-je déclarer un objet de celui-ci, à l'intérieur d'une fonction qui sera allouée sur la pile et non sur le tas?
En d'autres termes, je veux éviter d'utiliser le «nouveau» mot-clé pour celui-ci. Ce code est mauvais : xxx

Je sais quelle pile / tas sont parfaitement et j'ai entendu parler du merveilleux c # gc, mais j'insiste pourtant Allouer cet objet minuscule, qui n'est ici que pour la commodité, sur la pile.

Cette attitude vient de C ++ (mon outil principal) afin que je ne puisse pas ignorer cela, je veux dire que cela ruine vraiment le plaisir pour moi Ici (:


12 commentaires

Je suis à peu près sûr que vous ne pouvez pas faire cela en C #. Je ne sais pas si c'est possible dans .net, cependant, par IL.


@eldarerathis - Dans ce cas, je suis obligé d'utiliser c #.


Eh bien, vous devrez penser à C # aussi


@Poni: Ensuite, vous devriez probablement écrire C # au lieu d'essayer d'écrire C ++ en C #. Je ne comprends pas vraiment où le problème est, je suppose, mais c # /. Net est conçu de cette manière pour une raison.


Quel est le point de créer httpcontextex quand même? La classe existante httpcontext propose déjà une demande Demande et réponse propriété.


@John Rasch Je suis paresseux quand il s'agit de passer les mêmes six pointes de plus de 12 fonctions, quand je pouvais simplement passer un bel objet.


@Poni, il vous suffit de passer le httpContext, car il a la demande et la réponse en tant que propriétés ...


@Thomas levesque moins de taper est souhaité (: Je veux dire au lieu de "httpContext. ???" Je vais écrire "CTX.RES" ... comme ça.


Chaque développeur C # C # dit ici la même chose. Pourquoi demander si vous allez choisir d'ignorer les réponses?


@ Yodaj007 Votre question est "illogique" - repenser à ce sujet .... Astuce: Dire à l'avenir .....


Pour simplifier - je n'avais aucun moyen de savoir que ces types de réponses arriveraient, et si je saurais que ce sont les réponses que je ne demanderais pas, n'est-ce que je le ferais?!? De plus, la réponse d'AQWERT est la réponse, sans tout le "bla bla".


@Poni: La pile et le tas sont des détails de mise en œuvre dans le monde géré. La langue ne prend en charge que la notion de types avec une sémantique et des types de valeur avec la sémantique de référence. Si vous êtes intéressé à utiliser Value Semantitique pour httpcontextex , faites-en une structure. Sinon, faites-en une classe.


4 Réponses :


4
votes

Vous devez venir de C ++. Les choses ne fonctionnent pas comme ça dans .net.

Tous les types de référence sont alloués sur le tas géré, où ils sont suivis par le GC. Pour les références d'objet Scopées par une fonction qui quitte rapidement, les objets alloués ne subsistent probablement probablement que dans la génération 0 du tas géré, ce qui donne des collections de mémoire très efficaces. Le tas géré est syntonisé pour gérer des objets de courte durée de vie. Il n'a même pas la même stratégie d'allocation que le tas C ++ que vous puissiez être habitué à.

Voici comment fonctionne le CLR. Si vous voulez travailler d'une autre manière, essayez un runtime non géré.


0 commentaires

11
votes

Vous ne pouvez pas (et ne devrait pas) faire cela. Même si vous utilisez un struct (qui sera mis sur la pile), vous devez utiliser l'opérateur nouveau pour les classes contenues. Sur une note sérieuse, si vous passez à une autre langue, changez également vos attitudes.


22 commentaires

L'utilisation d'un vuetype dérivé pour obtenir une allocation de pile n'est qu'un artefact de la mise en œuvre actuelle du CLR. Il n'y a aucune obligation de le faire être ainsi dans la spécification.


Voir Eric Lippert's "La pile est un détail de mise en œuvre, la première partie", blogs.msdn.com/b/ericlippert/archive/2009/04/27/...


@CODAIIZEN: Lors de la rédaction de code de haute performance, quelle importance est la mise en œuvre actuelle de la plate-forme (et des changements probables dans un proche avenir), pas une autre autre implémentation théorique que la spécification pourrait permettre. Cela dit, j'ai tendance à accepter que cette classe ne soit pas une structure.


Si vous êtes après la performance qui peut différer entre l'utilisation du tas et la pile, vous devez rechercher une autre langue que la langue gérée gérée.


@CODAIZEN Pourriez-vous expliquer un peu plus sur ce que vous avez dit?


@Poni: Bien que les structures puissent être utiles, elles devraient être immuables et petites (par exemple 16 octets ou moins), comme chaque fois qu'ils sont transmis à un sous-programme, tout le morceau de la mémoire représentant l'objet est copié, à moins que vous ne le souhaitiez Utilisez ref dans tous vos arguments de la fonction. Dans plus de 5 ans ou plus de développement C #, je n'ai pas encore trouvé de cas où je devais m'inquiéter de la vitesse de pile .NET / tasse de tas. En bref, je déclare juste des cours et laissez-vous s'inquiéter de cela, alors que je me concentre sur l'application.


Il a dit que "la pile" n'est qu'un détail de mise en œuvre. Cela pourrait être parti dans la prochaine version du .NET Framework, ou le comportement des valeurs de valeur pourrait changer. Lisez les entrées de blog Tuzo liées à, c'est par l'un des implémentations des trucs de niveau bas.


Je suis en désaccord, je pense que .NET est une plate-forme valide pour écrire un code quelque peu rapide, et lors de l'optimisation, il fait parfois une différence si vous utilisez «structure» ou «classe», mais ses caractéristiques de performance sont différentes de C ++ et cela ressemble à l'OP décrit une micro-optimisation qui n'améliorera probablement pas les performances de .NET.


C'est exactement ce que je disais, bien que d'une manière peu différente.


@Qwertie Je suis d'accord avec ce que vous avez dit. Tout. Sérieusement. Pourtant, vous savez que c'est une question de bonne pratique, plus que la recherche d'une optimisation


Je choisis souvent «struct» pour les structures de 4 à 16 octets, mais je le fais principalement pour économiser de la mémoire dans de grandes collections, pas autant pour éviter les allocations de tas. Un point important est que l'allocation de tas (plus la collecte des ordures) est souvent plus rapide en C # que l'allocation (plus de distribution) en C ++. Le CLR .NET, contrairement aux implémentations typiques C ++, est spécifiquement optimisé pour créer de grandes quantités de petits objets de tas temporaires. J'encourage l'OP à faire du profil pour le vérifier pour vérifier cela.


@Femarf Vous savez quoi, je vais vous dire ceci - je vais accepter de manière heureuse (mineure) sur mon code C # si je serai en mesure de conserver mes habitudes C ++.


Si cela flotte votre bateau, d'accord - j'espère juste (pour vous) cela flotte également votre bateau de votre employeur.


Hahahahahahahaha aaaaaaaaaa !! Mon chat, assis ici, j'ai juste sauté Coz de mon rire! Tu m'as tué .. (: tu as définitivement mon +1 !!!


Whoa, poni. Vous êtes prêt à prendre une performance frapper pour éviter les meilleures pratiques en C #? Vous savez, alloué sur la pile n'est même pas votre habitude, c'est l'habitude du compilateur ou de l'exécution. Vous déclarez simplement une variable, le compilateur / Runtime décide où le mettre. Alors, qu'est-ce que vous dites, c'est .... vous voulez que le temps d'exécution .NET assume les habitudes de votre compilateur C ++?


@Qwertie C'est comme dire que les gens ne tuent pas les gens - ce sont des armes à feu qui tuent des gens. Ce que je dis, c'est que mon PC est mon PC et je vais le faire se comporter comme je le disais, et quand je dis affecter sur la pile, cela le fera - en plus de quelque chose qui n'était pas ce n'était pas mentionné ci-dessus avant - si vous allociez du tas, cela signifie que le cadre net verrouille au moins une serrure (mutex, section critique, etc.), tandis que si les désigers étaient intelligents (que je crois qu'ils étaient), ils ont fait la répartition de la pile, comme dans n'importe quelle application normale "Native Code".


Clarifier mon dernier commentaire; Le tas signifie qu'il est partagé (par plusieurs threads), la pile signifie qu'il est appartenant au fil actuel, donc aucun verrouillage nécessaire.


@Qwertie Je tiens également à dire que lorsque je veux allouer sur la pile, comme indiqué, j'attends effectivement que c # me permet de décider où il est préférable que cet objet spécifique soit attribué à cet objectif. COMPILER décide? Pas toujours. Prenez le mot-clé C ++ 'volatile' par exemple - il fait un changement extrême sur une seule variable. Et c'est la décision du codeur, alors qu'il pouvait le laisser au compilateur pour en décider et prier pour de bien ...


C # ne vous laissera pas choisir sur une base par objet si vous souhaitez mettre un objet sur la pile ou le tas. Le plus proche que vous puissiez venir est de déclarer une structure x {...}, puis déclarez classes y {public x x; } .... alors vous utiliseriez x pour la pile, y pour le tas. Mais je n'ai jamais eu vraiment besoin de faire ça.


@Poni: Malheureusement, vos trois derniers commentaires indiquent que C ++ a causé des dommages irréversibles à votre psychisme et la capacité de penser de manière abstraite sur les logiciels. Les définitions que vous avez données d'une pile vs un tas fait mon cerveau exploser. Vous présumez beaucoup trop sur la mise en œuvre sous-jacente.


@Greg D jusqu'à présent, tout ce que j'entends de la plupart des C # 'ers ici est que je devrais " laisser le cadre faire le travail - excuse moi si quelqu'un qui vient de C ++ Je ne peux pas tolérer de telles choses. Encore plus, je doute des capacités de programmation / compétences de la plupart des gourous ici, selon la discussion "intelligente" dans cette question légitime , qui semble simplement il y a une "race" de programmeurs qui s'appuient sur Microsoft faire le travail (sans infraction MS). Enfin, cette question est allée trop loin sur sa tête et je remercie à nouveau à Aqwert pour la simple réponse souhaitée. Heureux codage tout! =)


Si vous pouvez accepter que différentes langues ou cadres font des choses différemment - excuse Moi si un programmeur à ciel ouvert pense que d'autres plates-formes peuvent faire les choses différemment en comparaison à celles que vous utilisez - alors juste seulement t Programme en eux.



14
votes

Si vous l'avez changé à un type de valeur à l'aide de struct code> et créez une nouvelle instance dans le corps d'une méthode, elle le créera sur la pile. Cependant, les membres, tels que ce sont des types de référence, seront toujours sur le tas. La langue, que ce soit une valeur ou un type de référence nécessitera toujours le nouvel opérateur, mais vous pouvez utiliser var code> pour éliminer la double utilisation du type de type

var ctx = new HttpContextEx(); 


2 commentaires

"Mais vous pouvez utiliser var pour éliminer la double utilisation du nom de type" << a eu un bon rire avec celui-ci (: de toute façon, réponse cristalline, je vous remercie pour le soutien!


Juste pour que je puisse lier ce Great Article par Eric Lippert - Les types de valeurs sur la pile sont un détail de mise en œuvre de tous les cours actuels, mais ils pourraient être aussi stockés sur le tas. ( 2 )



1
votes

dans les classes .NET sont des types de référence et les structures sont des types de valeur.

Si vous voulez vraiment que le type attribué sur la pile, vous pouvez faire une structure. Il y a cependant plusieurs raisons pour ne pas: P>

  • Les structures sont plus compliquées à mettre en œuvre correctement. Vous devez vous en tenir aux cours jusqu'à ce que vous ayez une bonne raison de créer une structure. Li>
  • Les structures sont destinées aux types qui représentent une seule unité, tandis que votre type n'est qu'un conteneur pour trois unités distinctes. LI>
  • Une structure ne doit pas dépasser 16 octets pour fonctionner efficacement. Sur un système 32 bits, vous obtenez sous cette limite, mais sur un système 64 bits, la structure est supérieure à celle. LI>
  • Une structure doit être immuable pour fonctionner de manière à fonctionner comme un type de valeur, que votre type n'est pas. LI> ul>

    Enfin, il n'y a rien de mal à l'affichage de petits objets sur le tas. Le gestionnaire de mémoire est en fait conçu spécifiquement pour gérer efficacement de petits objets de courte durée. P>

    Voici un exemple de code qui ne fonctionne pas si c'est une structure, mais fonctionne bien si c'est une classe: P >

    public void SetContext(HttpContextEx ex) {
      ex.context = HttpContext.Current;
      ex.req = ex.context.Request;
      ex.res = es.context.Response;
    }
    
    HttpContextEx ctx = new HttpCoontextEx();
    SetContext(ctx);
    


2 commentaires

Concernant le code; Je comprends que. Je comprends aussi que en mettant le mot-clé "ref '" je suis défini. Correct, non?


@Poni: Vous pouvez utiliser le mot-clé ref pour faire fonctionner ce code, mais il existe d'autres situations similaires dans lesquelles une structure qui n'est pas implémentée ne fonctionne pas correctement à fonctionner.