C'deki “yıkıcıları” atlamak YAGNI'yı çok mu ileri götürüyor?


9

OO benzeri teknikleri kullanarak C orta gömülü bir uygulama üzerinde çalışıyorum. "Sınıflarım", kapsülleme, polimorfizm ve bağımlılık enjeksiyonunu taklit etmek için veri yapıları ve işlev işaretçileri yapılarını kullanan .h / .c modülleridir.

Şimdi, bir myModule_create(void)fonksiyonun bir myModule_destroy(pointer)muadili ile gelmesi beklenir . Ancak proje gömülüyor, gerçekçi bir şekilde başlatılan kaynaklar asla serbest bırakılmamalıdır.

Yani, 4 UART seri portum varsa ve gerekli pinleri ve ayarları ile 4 UART örneği oluşturursam, çalışma zamanında bir noktada UART # 2'yi yok etmek için kesinlikle hiçbir neden yoktur.

Peki YAGNI (buna ihtiyacınız olmayacak) prensibine göre yıkıcıları atlamalı mıyım? Bu bana çok garip geliyor ama onlar için bir fayda düşünemiyorum; kapatıldığında kaynaklar serbest bırakılır.


4
Nesneyi elden çıkarmanın bir yolunu sağlamazsanız, oluşturulduklarında "sonsuz" ömürleri olduğu açık bir mesaj iletiyorsunuzdur. Bu, uygulamanız için mantıklıysa, diyorum: yapın.
glampert

4
Eğer tipi kendi kullanım durumunuzla birleştirmek için bu kadar ileri gidecekseniz, neden bir myModule_create(void)fonksiyonunuz var? Kullanmayı beklediğiniz belirli örnekleri açıkta bıraktığınız arabirime kodlayabilirsiniz.
Doval

@ Düşündüm Düşündüm. Ben amirimden kod parçalarını ve parçalarını kullanan bir stajyerim, bu yüzden "doğru yapmak" ile uğraşmaya, deneyim ve şirket standartlarına uyum için C'de OO stilini denemeye çalışıyorum.
Asics

2
@glampert çiviler; Oluşturma işlevinin belgelerinde beklenen sonsuz ömrünü temiz hale getirmeniz gerektiğini ekliyorum.
Blrfl

Yanıtlar:


11

Nesneyi elden çıkarmanın bir yolunu sağlamazsanız, oluşturulduklarında "sonsuz" kullanım ömrüne sahip olduklarına dair net bir mesaj iletiyorsunuzdur. Bu, uygulamanız için mantıklıysa, diyorum: yapın.

Glampert haklı; burada yıkıcılara gerek yok. Onlar sadece kod şişmesi ve kullanıcılar için bir tuzak oluşturacaktır (yıkıcı çağrıldıktan sonra bir nesneyi kullanmak tanımsız davranıştır).

Ancak, nesneleri atmaya gerçekten gerek olmadığından emin olmalısınız. Örneğin, şu anda kullanımda olmayan bir UART için bir nesneye mi ihtiyacınız var?


3

Bellek sızıntılarını tespit etmenin en kolay yolu, uygulamanızdan temiz bir şekilde çıkabilmektir. Birçok derleyici / ortam, uygulamanızdan çıkıldığında hala ayrılan belleği kontrol etmenin bir yolunu sunar. Biri sağlanmazsa, çıkmadan hemen önce bazı kodları eklemenin bir yolu vardır.

Bu nedenle, "teorik olarak" hiçbir zaman bellek sızıntısı algılama kolaylığı için asla çıkmaması gereken gömülü bir sistemde bile kurucuları, yıkıcıları ve kapatma mantığını sağlayacağım. Gerçekte, uygulama kodunun asla çıkmaması durumunda bellek sızıntısı tespiti daha da önemlidir.


Bellek ayırma aygıtlarında ciddi olarak düşündüğüm bir desen olan, ayırma yaptığınız tek zaman başlangıç ​​sırasında bu geçerli değildir.
CodesInChaos

@Kodlar: Kendinizi sınırlamak için bir neden yok. Başlangıçta hafızayı önceden tahsis eden harika bir tasarıma sahip olsanız da, sizden sonra bu büyük şemaya özel olmayan veya önemini göremeyen insanlar, sinek ve tasarım gidiyor. Sadece doğru yapın ve uyguladığınız şeyin gerçekten işe yaradığını doğrulayın / ayırın ve doğrulayın. Gerçekten bellek kısıtlı bir cihazınız varsa, tipik olarak yapılan yeni operatör / malloc'u geçersiz kılmak ve ayırma bloklarını önceden korumaktır.
Dunk

3

OO benzeri bir yaklaşımı teşvik etmek için opak veri türlerini kapsamlı bir şekilde kullanan gelişimimde, bu soru ile de güreştim. İlk başta, yıkıcıyı YAGNI perspektifinden ve MISRA “ölü kod” perspektifinden elimine etme kararındaydım. (Ben kaynak odası bol vardı, bu bir düşünce değildi.)

Bununla birlikte ... bir yıkıcı eksikliği, otomatik birim / entegrasyon testinde olduğu gibi testi zorlaştırabilir. Geleneksel olarak, her test nesnelerin yaratılabilmesi, manipüle edilebilmesi ve sonra imha edilebilmesi için bir kurulum / sökme işlemini desteklemelidir. Sonraki test için temiz, lekesiz bir başlangıç ​​noktası sağlamak için yok edilirler. Bunu yapmak için sınıfın bir yıkıcıya ihtiyacı var.

Bu nedenle, benim tecrübelerime göre, YAGNI'deki "değil" bir "vardır" olduğu ortaya çıktı ve sonunda ihtiyacım olup olmadığını düşünürsem her sınıf için yıkıcı yarattım. Testi atlasam bile, beni takip eden fakir slob için en azından doğru tasarlanmış bir yıkıcı var. (Ve çok daha düşük bir değere göre, kodun yok edileceği bir ortamda kullanılabilmesi için kodu daha yeniden kullanılabilir hale getirir.)

Bu YAGNI'yi ele alırken, ölü kodu ele almaz. Bunun için, #define BUILD_FOR_TESTING gibi koşullu bir derleme makrosunun, yıkıcının son üretim yapısından çıkarılmasına izin verdiğini görüyorum.

Bu şekilde yapın: test / gelecekteki yeniden kullanım için yıkıcıya sahipsiniz ve YAGNI ve "ölü kod yok" kurallarının tasarım hedeflerini yerine getiriyorsunuz.


Test / ürün kodunuzu # ifdefing konusunda dikkatli olun. Açıkladığınız gibi tüm bir işleve uygulandığında oldukça güvenlidir, çünkü işlev gerçekten gerekliyse derleme başarısız olur. Bununla birlikte, şimdi prod'da çalışandan farklı bir kod yolu test ettiğiniz için bir işlev içinde #ifdef satır içi kullanmak çok daha risklidir.
Kevin

0

Operasyon yok edici bir yıkıcıya sahip olabilirsiniz,

  void noop_destructor(void*) {};

sonra Uartbelki de

  #define Uart_destructor noop_destructor

(gerekiyorsa uygun dökümü ekleyin)

Belgelemeyi unutmayın. Belki sen bile istersin

 #define Uart_destructor abort

Alternatif olarak, yıkıcı işaretçi işlevi NULLonu çağırmaktan kaçınmak durumunda, yıkıcıyı ortak kod çağıran özel durum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.