2014-07-14 60 views
8

Sık sık RAII ile karşılaştığım bir sorun. Bunun için iyi bir çözüm olup olmadığını merak ediyordum. Standart RAII yarar sınıfı ileRAII ve çıkarılan şablon argümanları

Başlangıç:

class RAIIHelper { 
    RAIIHelper() { 
    AcquireAResource(); 
    } 
    ~RAIIHelper() { 
    ReleaseTheResource(); 
    } 
}; 

Şimdi, çeşitli nedenlerle, ben bir şablon yapmak gerekir.

template <typename T> 
class RAIIHelper { 
    RAIIHelper(T arg) { 
    AcquireAResource(); 
    } 
    ~RAIIHelper() { 
    ReleaseTheResource(); 
    } 
}; 

Şimdi bir kullanım site olduğunu düşünün: Diyelim ayrıca yapıcı şablon parametresi türünde bir argüman alır demek

O someObj türeyemez zaman SomeType dışarı yazmak zorunda can sıkıcı
void func() { 
    RAIIHelper<SomeType> helper(someObj); 
} 

,

template <typename T> 
RAIIHelper<T> makeRAIIHelper(T arg) { 
    return RAIIHelper<T>(arg); 
} 

Şimdi öylesine gibi kullanabilirsiniz:

yüzden tipini anlamak için bir yardımcı işlev yazmak
void func() { 
    auto helper = makeRAIIHelper(someObj); 
} 

Harika, değil mi? Bir çakışma var: RAIIHelper'un artık kopyalanabilir veya hareketli olması gerekiyor ve kaynağın serbest bırakıldığı yıkıcı - potansiyel olarak iki kez çağrılabilir: bir kez makeRAIIHelper tarafından döndürülen geçici için ve bir kez de arama işlevindeki yerel değişken için.

Pratikte, derleyicim RVO'yu gerçekleştirir ve yıkıcı sadece bir kez çağrılır. Ancak, bu garanti edilmez. Bu, RAIIHelper bir = delete 'd hareket ettiricisini vermeye çalışırsam, kodun artık derlemediği gerçeğinden görülebilir. o taşındı-den geçirildikten sonra ReleaseTheResource() aramamamı bilmesi

Ben RAIIHelper için ek devlet ekleyebilir, ama bu tür kesinti almak için makeRAIIHelper() eklemeden önce gereksiz ekstra bir iş.

RAIIHelper adresine ekstra durum eklemek zorunda kalmadan tür kesintisi alabilmemin bir yolu var mı?

+0

Orada 'unique_ptr' i yeniden keşfediyor gibi bakıyorum, 'SomeType' türünde hiçbir doğal sentinel nesne olmadığından emin misiniz? – Deduplicator

+0

'unique_ptr' kullanabilirsiniz. –

+0

Uygun bir hareket ettiriciyi yazın ve kopya oluşturucuyu devre dışı bırakın. Bu bir sorun olmamalı. –

cevap

8

Çok basit bir çözüm var: Yerel bir değişkene kopyalamak yerine geçici nesneye bir başvuru kullanın. önceki cevaplar ve yorumlar üzerine

void func() 
{ 
    auto&& helper = makeRAIIHelper(someObj); 
} 
+5

Ve "RAIIHelper (arg)" i değiştirirseniz, "doğrudan başlatma" à la 'return {arg}' ile birlikte, türün hareketli olması gerekmez. – dyp

+0

Geçici nesne kapsam dışına çıktığında bu bir sonraki satırda nasıl çalışır? –

+4

@ StianV.Svedenborg Bu geçici sürenin ömrü, kapsamın sonuna kadar uzatılmıştır. – dyp

1

Bina:

Sen unique_ptr için hareketli olmanın sorumluluğunu bırakın ve bu gibi kaynak geri dönebilirler: Artık

template <class T> 
auto makeRAII(T arg) -> std::unique_ptr<RAIIHelper> { 
    return make_unique(RAIIHelper<T>(arg)); 
} 

statik gibi kapsamları değişken, ancakunmovable olabilir.

+0

Bu işe yarıyor, ancak gereksiz bir dinamik ayırmanın yükünü dayatıyor. – HighCommander4

+0

Nesnenin ömrüne ve geliştiricinin (iyi bir şey) tembelliğine bağlı olarak buna değer olabilir ya da olmayabilir. –