2016-04-02 19 views
1

Geri Döndürme Bir String sınıfı MyString (evet, ödev olarak) yazıyorum ve bir unique_ptr<char[]> (ve Vector değil) döndüren bir toCString yöntemi sunmak zorundayım. Ne yazık ki, işaretçiyi arayan kişiye döndürürken başarısız olurum: Sonuç her zaman yanlış içerikle doldurulur - yığınta işaretçiyi ve/veya karakter dizisini oluşturduğum anlaşılıyor. Hata ayıklama yaparken, her zaman beklenen davranışı alırım. Sorunlar sadece arayanlar sitesinde gerçekleşir. Benim hatam nerede?Eşsiz bir ptr

+1

Neden akıllı işaretçi geri dönüyor? _C_ dize, "char" (ve bir diziye değil) için yalnızca bir işaretçidir – ForceBru

+1

'unique_ptr (karakterler)' Bu bir anlam ifade etmez ve derlemez. Gerçek kodunuzu gösterin. –

+0

Akıllı göstergeyi yığında referans olarak ayırıyorsunuz, ardından işlevden çıkıyorsunuz. Bu davranış doğru görünse bile tahmin edilemez davranışlar üretecektir. http://stackoverflow.com/questions/10643563/how-to-return-smart-pointers-shared-ptr-by-reference-or-by-value –

cevap

4

ama bu sorunu çözmez. İstemci tarafında sorun oluşuyor çünkü c-dizgisini null olarak sonlandırmıyorsunuz.

Ne tür m_string olduğunu bilmiyorum, bu yüzden bir an için bir std :: string olduğunu varsayalım. Sen gerçek yöntemleri kendini çevirebilir: Christophe'un öneri gereğince

std::unique_ptr<char[]> MyString::toCString() const 
{ 
    // get length (in chars) of string 
    auto nof_chars = m_string.size(); 

    // allocate that many chars +1 for the null terminator. 
    auto cString = std::unique_ptr<char[]>{new char[nof_chars + 1]}; 

    // efficiently copy the data - compiler will replace memcpy 
    // with an ultra-fast sequence of instructions in release build 
    memcpy(cString.get(), m_string.data(), nof_chars * sizeof(char)); 

    // don't forget to null terminate!! 
    cString[nof_chars] = '\0'; 

    // now allow RVO to return our unique_ptr 
    return cString; 
} 

, burada yine, std :: copy_n açısından yazılı bir yöntem. Std :: copy [_xxx] işlev grubunun hepsinin son yazılanı geçtiği bir yineleyici döndürdüğünü unutmayın. Boş sonlandırıcının yerini yeniden derlemek için kullanabiliriz. Standart kütüphane harika değil mi?

std::unique_ptr<char[]> MyString::toCString() const 
{ 
    // get length (in chars) of string 
    auto nof_chars = m_string.size(); 

    // allocate that many chars +1 for the null terminator. 
    auto cString = std::unique_ptr<char[]>{new char[nof_chars + 1]}; 

    // efficiently copy the data - and don't forget to null terminate 
    *std::copy_n(m_string.data(), nof_chars, cString.get()) = '\0'; 

    // now allow RVO to return our unique_ptr 
    return cString; 
} 
+0

Görünüşte, nesne 'm_string', 'm_start' ve' m_len'’in bir alt dizesini temsil eder. Ancak alan yaratma ve NUL terminatörü ekleme konusunda kesinlikle haklısınız. –

+0

[eski 'memcpy()' işlevinin 'std :: copy()' veya 'std :: copy_n()'] ile değiştirilmesi anlamlı olmaz mıydı (http://stackoverflow.com/questions/4707012/kullanması daha iyi-stdmemcpy-veya-stdcopy-in-terms-to-performance)? – Christophe

+0

@Christophe, daha akılcı olacaktı. –

2

Yaptığınız gibi bir unique_ptr'ye başvuru oluşturmayın. Hareket yapıcı herşeyi ilgilenir: Bunun yerine, doğrudan unique_ptr dönmek Ben kabul edilen bir yanıt zaten orada bkz

return unique_ptr<char[], default_delete<char[]>>(characters); 
+0

Ayrıca C++ derleyicinin C++ 11'i desteklediğinden ve etkinleştirdiğinden emin olun. –

+2

@NathanielJohnson elbette! Öte yandan, eğer 'unique_ptr' kullanır ve kullanımdan kaldırılmış 'auto_ptr' kullanırsa ve dahası onunla bazı kodları derlerse, C++ 11'in verildiğini varsayabilirim ;-) – Christophe

+1

ne demek istediniz? Dönüş Değeri Optimizasyonu her şeyle ilgilenecektir ". Değerin verimli bir şekilde geri dönmesi, bir hareket ettiriciye bile gerek duymaz. –

1
sorunuzu düzenledikten yana

ve şimdi

unique_ptr<char[]> cString = unique_ptr<char[]>{new char[m_len]}; 

İlk gelişme kullanıyor: auto kullanmak

auto cString = unique_ptr<char[]>{new char[m_len]}; 

İkinci gelişme: Etiketinizde, C + 11 ama eğer C + 14'ü kullanıyorsunuz, daha sonra 'u şu şekilde kullanın:

auto cString = std::make_unique<char[]>(m_len); 

Ayrıca Scott Meyers'in dediği gibi C + 11'i kullanıyorsanız, make_unique işlevini kendiniz yazmanız yeterli. Bu zor değil ve çok kullanışlı.

http://ideone.com/IIWyT0

template<class T, class... Types> 
inline auto make_unique(Types&&... Args) -> typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type 
{ 
    return (std::unique_ptr<T>(new T(std::forward<Types>(Args)...))); 
} 

template<class T> 
inline auto make_unique(size_t Size) -> typename std::enable_if<std::is_array<T>::value && std::extent<T>::value == 0, std::unique_ptr<T>>::type 
{ 
    return (std::unique_ptr<T>(new typename std::remove_extent<T>::type[Size]())); 
} 
İlgili konular