7
votes

Est-ce que ce cours de classe de style Raii sera-t-il fonctionner?

sous C ++, j'ai une classe mutex code>, et j'utilise cette classe de style Raii pour vous assurer que le mutex est déverrouillé, quelle que soit la raison du retour de la méthode:

NSLock *_lock;    // instance variable

- (void)myFunc {
    Locker *locker = [[Locker alloc] init];
    locker.lock = _lock;

    return;     // Whenever I like
}


11 commentaires

Une chose qui se voit dans mon esprit est que [casier-casierwithlock: _lock] pourrait renvoyer un objet Autorélied, qui pourrait ne pas être immédiatement distribué lorsqu'il est hors de portée (en fonction des optimisations effectuées par le compilateur Arc ).


@Martinr Même avec la mise en œuvre ci-dessus de retour [[casier Alloc] initwithlock: verrouillage]; ?


Oui (je viens de l'essayer), parce que vous l'enveloppez dans [casier-casierwithlock: _lock] . Si vous appelez directement casier * caser = [[[casier Alloc] initwithlock: _lock] dans myfunc alors il sera libéré immédiatement.


@Martinr Que diriez-vous de casier * casier = [[[casier Alloc] init]; caser.lock = _lock; et effectue la serrure dans le setter? (c'est-à-dire se débarrasser sur la méthode de commodité au niveau de la classe).


Je garderais initwithlocker: _lock et exécutez la verrouillage de la méthode init, qui est bien symétrique avec le déverrouillage dans DealLoc. Si vous vous inquiétez de la "variable non utilisée" AVERTISSEMENT, vous pouvez ajouter casier = nil à la fin du corps de la fonction.


@Martinr ouais, c'est un peu ce que j'essaie d'éviter; Il n'y a pas besoin de ce genre de classe de cours, sauf lorsque j'oublie de faire la chose cruciale. J'ai changé la mise en œuvre, que je pense est à la fois en terres et fait ce qu'elle devrait (à moins que je n'ai pas manqué autre chose).


Oui, ça va bien pour moi. Donc, la seule chose était le problème de l'autorelease, mais vous avez déjà une réponse pour cela (je devrais écrire des réponses au lieu de commentaires :-)


C'est une idée intelligente! Pourquoi les vérifications explicites pour non-NIL dans le setter?


@JOSHCASWELL C'est donc nous assurons que nous sommes sûrs de verrouiller et de déverrouiller lorsque nous avons été transmis une serrure ou effacez la serrure.


Je ne pense pas que vous en avez besoin, à moins que vous ne le pense plus lisible. Si votre ivar, _lock , est nil au début du setter, déverrouiller ne fera rien, et de même après _lock = verrouillage ; Si verrouillage était nil - [nil verrouillage]; est un non-op.


@Joshcaswell ouais qui est vrai en fait. Merci.


4 Réponses :


3
votes

Je dirais que les méthodes de classe tels que xxx

provoqueraient probablement l'arc d'autoriser la valeur de retour (voir Cet article ). Je pense que ce sera autoritéé à moins que le nom de la méthode commence par alloc , nouveau , init , copie , Mutablecopy (ou sauf si vous utilisez des macros spéciales pour forcer le compilateur à ne pas autoréliquement, La documentation de Clang Arc est jolie Bon . Un objet Auteledeled serait évidemment un problème étant donné que votre serrure ne serait pas déverrouillé tant que la piscine de l'autorelease n'est pas égouttée.

J'ai toujours pensé à Raii comme étant une chose C / C ++ où vous pouvez attribuer des objets statiquement. Mais je suppose que vous pouvez le faire de cette façon, tant que vous ferez bien sûr que les objets ne sont pas autorélichés.


4 commentaires

+1 a accepté, comme indiqué par @martinr dans les commentaires. J'ai modifié la mise en œuvre maintenant pour éviter de telles méthodes. Pouvez-vous penser à une raison pour laquelle cela ne fonctionnerait pas?


Cela me fait peur un peu, mais je ne peux vraiment penser à rien. L'objet doit être traité dès que la "version" insérée par l'ARC est appelée, qui devrait être lorsque la portée du casier * est excitée ...


Eh bien, je ne peux pas le tester pour le moment, car cela fait partie d'un grand nouveau morceau de fonctionnalité, mais une fois que c'est prêt, je vais lui donner un bon test et revenir avec les résultats.


Je vaut la peine de lire la section d'optimisation clang.llvm.org/docs/...



4
votes

Si vous voulez des motifs RAII, vous devez utiliser Objective-C ++ et écrire des cours C ++ Raii.

ARC est peu susceptible de vous donner le résultat que vous voulez. L'objet peut être traité trop tard, si quelque chose le cause d'être autorété. L'objet peut être traité trop tôt, si l'optimiseur ARC décide que l'objet n'est plus utilisé.


1 commentaires

C'est certainement une option; Mon application actuelle est à 100% de l'objectif-C ++ de toute façon, de sorte que ce ne serait pas un problème. Pensez-vous que ce serait plus résilient? Je l'ai testé avec succès (voir le GIST dans ma question), la mise en œuvre de l'objectif-C proposé apparaît bien fonctionner.



7
votes

Better API: Utilisez un bloc:

NSLock *someLock = ...;
performBlockWithLock(someLock, ^{
    // your code here
});


1 commentaires

+1 Pas une mauvaise idée Rob. Comme le code de mon application est tout Objective-C ++, j'utilise My C ++ Raii-style MuTExlock à la place, pour garantir la distraction, quoi qu'il arrive.



-1
votes

Ne fais pas ça! J'ai récemment chassé des bugs pendant une journée ou donc jusqu'à ce que j'ai découvert Tima et que l'ordre des objets libérés via Arc est un peu aléatoire, un peu de temps après que la dernière référece disparaisse. Il semble que les pools de libération automobile sont peuplés un peu au hasard. L'ordre n'est pas préservé. C'est-à-dire un objet enfant référencé que par un autre objet a été distribué après son objet parent. J'ai fini par faire de la ressource manuelle DeinInit via des messages "destruct" auto-fabriqués et finira de manière proportionnellement de portage tout sauf de code de colle à C ++. Je suis désolé pour les gens qui devaient utiliser Swift. Fondamentalement, tous les problèmes que vous avez avec GC ....


0 commentaires