2014-08-29 20 views
8

Sırasız kapsayıcılar kullanan bir (C++) kitaplığı geliştiriyorum. Bunlar, sakladıkları elemanların türleri için bir (genellikle std::hash şablon yapısının bir uzmanlaşması) bir kesici gerektirir. Benim durumumda, bu öğeler, the bottom of this page adresindeki örneğe conststr benzer şekilde dizgi değişmezlerini kapsülleyen sınıflardır. here, in the 'Notes' section açıklandığı gibi STL, ancak, sadece işaretçileri hesaplar sabit karakter işaretçiler, bir uzmanlık sunmaktadır:Eşit dizgi değişmezlerinin aynı adreste depolanıp depolanmadığını kontrol edin

C dizeleri için hiçbir uzmanlaşma yoktur. std::hash<const char*> işaretçinin (bellek adresi) değerinin bir karmasını üretir, bu herhangi bir karakter dizisinin içeriğini incelemez.

this question açıklandığı gibi bu (ya da ben öyle düşünüyorum), bu birkaç eşit dize hazır aynı adreste saklanır olsun standart C++ tarafından garanti edilmemektedir çok hızlı olmasına rağmen. Eğer böyle değilse, hashers ilk koşul yerine getirilmeyecektir:

iki parametre k1 ve eşit k2 için

, std::hash<Key>()(k1) == std::hash<Key>()(k2)

Ben seçici kullanarak karma hesaplamak istiyoruz

Daha önce bahsi geçen garanti verilmişse uzmanlık sağlanmışsa veya başka bir algoritma sağlanmışsa. Başlıklarımı içerenlere sorma veya belirli bir makroyu tanımlamak için kitaplığımı oluşturma isteğine başvurmak mümkün olsa da, tanımlı bir uygulama tercih edilebilir.

Herhangi bir C++ uygulamasında makro var mı, ancak çoğunlukla g ++ ve argo, tanımı, aynı adreste birkaç eşit dize değişmezinin depolanmasını garanti eder?

Bir örnek:

#ifdef __GXX_SAME_STRING_LITERALS_SAME_ADDRESS__ 
const char str1[] = "abc"; 
const char str2[] = "abc"; 
assert(str1 == str2); 
#endif 
+2

Kesinlikle değil, çünkü sadece "* aynı adreste depolanan * eşit dizgiler" değil, daha büyük bir dizenin alt dizeleri olarak depolanan çok sayıda dizedir. Örneğin, iki "lite" kelimesi "dünya" ve " merhaba dünya "', derleyici gibi kod üretebilir. data: bayt STR {h, e, l, l, o, w, o, r, l, d} ikincisi "STR". – Manu343726

+6

Dize değişmezleri birleştirilse bile, iki 'char []' değişkeni olmayacaktır. st1 == str2' asla doğru olmaz. –

+1

Kapsayıcınız için 'std :: string' kullanamaz mısınız?Veya char diziler? – quantdev

cevap

5

herhangi makro herhangi C++ uygulamasında, var mı, ama esas gr ++ ve çınlama, kimin tanım garanti birkaç eşit dize hazır aynı adreste saklanır mı?

  • gcc sahiptir -fmerge-constants option (bu değil bir garantidir): derleme karşısında özdeş sabitleri (dize sabitleri ve kayan nokta sabitlerini) birleştirmek için

Denemesi birimleri.

Bu seçenek, assembler ve linker destekliyorsa, en iyileştirilmiş derleme için varsayılan seçenektir. Bu davranışı engellemek için -fno-birleştirme-sabitleri kullanın.

-O, -O2, -O3, -Os düzeylerinde etkinleştirilmiştir.

Dize havuzu katı olması için birden fazla tampon için birden işaretçiler olarak, amaçlarının sağlar:

  • Visual StudioString Pooling ("Yinelenen Dizeleri eleyin" /GF seçeneği) vardır tek bir tampon için işaretçiler. Aşağıdaki kodda, s ve t aynı dizeyle başlatılır. MSDN char* dizeleri değişmezleri kullanmakla birlikte, const char* görünüşte de -fmerge-constants seçeneği vardır

    • clang kullanılmalıdır, ancak:

char *s = "This is a character buffer"; 
char *t = "This is a character buffer"; 

Not: Dize havuzu aynı belleği işaret etmelerine neden olmaktadır --help bölümünde bunun hakkında fazla bir şey bulamıyorum, bu yüzden gerçekten gcc'nin bir eş değeri olup olmadığından emin değilim: dize hazır depolandığı nasıl sabitleri

Neyse

ait

Disallow birleştirme uygulaması bağımlı (programın salt okunur kısmında bunları depolayan birçok) 'dir.

Aksine olası uygulama bağımlı kesmek üzerinde kütüphane bina yerine, ben yerine sadece C tarzı dizeleri std::string kullanımını önerebilir: beklediğiniz gibi bunlar tam davranacaktır.

Sen senin yerinde emplace() yöntemlerle sizin kaplarda std::string oluşturabilirsiniz:

std::unordered_set<std::string> my_set; 
    my_set.emplace("Hello"); 
+0

'std :: string', dinamik sınıflandırma ve istisna tehlikesini beraberinde getiriyor; ancak, tek bir standart çözüm gibi görünmesine rağmen, tekerleğin yeniden yaratılmasının yanı sıra, sınıflarım için karma algoritmanın yanı sıra. – Kalrish

+0

@Kalrish: evet, ancak dinamik ayırma etkisi sınırlı olacaktır çünkü dizeleriniz derleme zamanında bilinir (yani, uygulama başladığında tüm dizelerinizi ayırabilirsiniz). Bu eşikleri temiz ve taşınabilir bir şekilde görünüyor. Umarım bu yardımcı olur. – quantdev

+1

char * s = "Bu bir karakter tamponu"; C++ 'da artık geçerli değil (C++ 11'de kırılma değişikliği). Const char * s = "Bu bir karakter tamponu" olmalı; . – user515430

2

C++ dize hazır çalışır herhangi bir şekilde izin vermiyor olsa da, çirkin ama biraz çalışılabilir var dize değişmezlerinizi karakter dizileri olarak yeniden yazmanızın bir sakıncası yoksa, sorunun etrafından dolaşın.

template <typename T, T...values> 
struct static_array { 
    static constexpr T array[sizeof...(values)] { values... }; 
}; 

template <typename T, T...values> 
constexpr T static_array<T, values...>::array[]; 

template <char...values> 
using str = static_array<char, values..., '\0'>; 

int main() { 
    return str<'a','b','c'>::array != str<'a','b','c'>::array; 
} 

Bu sıfır dönmek için gereklidir. Derleyici, birden fazla çeviri birimi str<'a','b','c'>'u başlatsa bile, bu tanımların birleştirileceğini ve yalnızca tek bir diziyle sonuçlanacağını garanti etmelidir.

Bununla birlikte, bunu dizgi değişmezleriyle karıştırmamanız gerektiğinden emin olmalısınız. Herhangi bir dize değişmezi, şablon örnekleme dizilerinden herhangi birine eşit olanı karşılaştırmak için değil garanti edilir.

+0

Teşekkürler! Ne yazık ki, dize değişmezleri kütüphanemde kullanmak için _way_ daha rahat olurdu. Yine de, derleme zamanında karakter dizilerine dönüştürülebilirlerse ... – Kalrish

+0

@Kalrish Dize değişmezleri şablon argümanları olarak kullanılamaz ve dize değişmezleri "constexpr" işlevlerine aktarılabilir ve dizge indekslemesine izin verilir. Sabit ifadelerde dize değişmezleri, bir "constexpr" fonksiyon parametresindeki bir indeksleme işlemi, sabit bir ifade olarak nitelendirilmez. Elimden gelenin en iyisi, önişlemciyi korkunç bir şekilde kötüye kullanmak ve çok fazla gereksiz şablon örneğini zorlamak: '#define CHAR_AT (s, i) ((i) :: dizi: sizeof (s) == 2? str :: dizi: .. .) ' – hvd

+0

Kullanacağınız en uzun dizeyi desteklemek için bu 'STR' makrosunu genişletmeniz ve ardından 'STR (" abc ")' yi kullanmanız gerekir. Bence bu çok kötü bir fikir, ama dize hazırlayanlara izin verebileceğim tek şey bu. – hvd