2011-01-19 28 views
8

Böyle uzun bir soru için özür dilerim ama mümkün olduğunca açık olmaya çalışıyorum. Bu bir şekilde strings in C++ ile ilgili önceki soruyu izler. Ben NRDO güvenmeden, gereksiz bellek ayırma, olmadan bir işlevden std :: dize nasıl dönebileceğini anlamaya çalışıyorum. Ben NRVO güvenmek istemiyorum nedenleri şunlardır:STL takas dönüşü mü?

biz şu anda her zaman hata ayıklama modunda etkin olmayabilir desteklenmektedir bile
  • kullanmak derleyici tarafından desteklenmeyen
    • o

      si (... ne yazık ki, böylece hiçbir C++ 0x rvalue referanslar)

    Ben C++ 03 uyumlu bir çözüm gerektiğini unutmayın bazı durumlarda (example) başarısını etkiler dediklerim mplest by-referans-pass ve bu

    void test(std::string& res) 
    { 
        std::string s; 
        //... 
        res.swap(s); 
    } 
    

    gibi std :: takas yapmak Ama başarmak istiyorum ne yani, referans olarak geçmektedir olmadığı kadar değeriyle dönmek için daha doğal ve genellikle daha uygundur

    std::string test() 
    { 
        std::string s; 
        //... 
        return SOMETHING(s); 
    } 
    

    İdeal sadece "dönüş değeri" ile swap yapacağını ama C++ bunun nasıl görmüyorum: budur. Kopyalama yerine hareket eden zaten auto_ptr var ve ben aslında auto_ptr<string> kullanabilirdim, ancak dize nesnesinin kendisini dinamik olarak ayırmaktan kaçınmak isterim.

    Benim fikrim, bir kopya yapıcısı geri döndüğünde çağrıldığında, taşını taşımak için bir işlevden döndürülen bir dize nesnesini bir şekilde "etiketlemektir". Ya Kaçırdığım bazı ciddi sorunlar tüm bu mantıklı

    struct Str 
    { 
        struct Moveable 
        { 
         Str & ref; 
         explicit Moveable(Str & other): ref(other) {} 
        }; 
    
        Str() {} 
        Str(const std::string& other) : data(other) {} // copy 
        Str(Moveable& other) { data.swap(other.ref.data); } // move 
    
        Moveable Move() 
        { 
         return Moveable(*this); 
        } 
    
        std::string data; 
    }; 
    
    Str test() 
    { 
        Str s; 
        //... 
        return s.Move(); // no allocation, even without NRVO 
    } 
    

    Yani ... neden olur mu: Ben ne istiyorum tam olarak işlevi gören bu kod ile sona erdi? (Örneğin, ömür boyu bir sorun olup olmadığından emin değilim). Belki de zaten böyle bir fikri kütüphanede (kitap, makale ...) gördünüz ve bana bir referans verebilir misiniz?

    DÜZENLEME: As @ rstevens fark edildi, bu kod MSVC'ye özgüdür ve const olmayan geçici olmayanlar gibi g ++ altında derlenmez. Bu , bir sorundur, ancak bu uygulamanın yalnızca MSVC'ye özgü olduğunu varsayalım.

  • +0

    Ne sorduğundan emin değilim. Sadece kodunuzu düzeltmeniz gerekiyor mu? Tam olarak istediğini yaptığını söylüyorsun, ama - görebildiğim kadarıyla - derlememeli. –

    +2

    Dizeninizin COW olup olmadığını kontrol ettiniz mi? Eğer öyleyse, fazladan bellek ayırmaları olacaktır. Ayrıca std :: string'in bazı uygulamaları dizgiyi nesneye (dizge kısa olduğunda) yerleştirir, bunun yerine bellek ayırır. Bunların doğruluğu doğruysa, optimizasyon girişimleriniz azaltmaktan ziyade maliyeti artırabilir. –

    +0

    @Charles: Kod, neyi başarmaya çalıştığımı açıklamak için var, ve eğer doğru görüp görmediğimde ve eğer bunun iyi bir şekilde uygulanması durumunda soru. –

    cevap

    4

    Yükseltme kullanımı, Boost.Thread gibi kitaplıklar için dahili olarak semantik öykünmesini kullanır. Uygulamaya bakmak ve benzer bir şey yapmak isteyebilirsiniz.

    Düzenleme: orada bir kütüphane Boost.Move aslında aktif bir gelişmedir, bu nedenle zaten kullanmaya başlayabilirsiniz.

    0

    Gerçekten değer döndürmenin uygulamanızda bir performans sorunu olduğunu belirlediniz mi? Bu, gitmenin en basit/en kolay yolu gibi görünüyor ve daha modern bir derleyiciye yükselttiğinizde rvalue referansları kullanabilirsiniz.

    s imha sırasına göre soruyu cevaplayamıyorum Movable 'in referansıyla. Derleyiciniz için siparişin ne olduğunu görmek için çeşitli kurucu ve yıkıcılara kod koyabilirsiniz.Tamam görünüyorsa bile, okuyucunun kafa karışıklığını önlemek ve muhtemelen alternatif bir derleyiciyi kırmak için ana hatlarıyla çizdiğiniz normal kalıplardan birini kullanmayı düşünmekteyim.

    +1

    Bu sadece bir optimizasyon meselesi değil, tipik kullanımı etkilediği için - geliştiricilerin değere göre dönüşün ucuz olduğunu bilmedikçe, bunu yapmaktan kaçınmaya çalışacaklardır. İnsanlar, erken optimizasyonun kötülük olduğunu söylemiş olsanız bile, yine de optimal bir kod yazmayı dener. –

    1

    Bu kodu g ++ üzerinde kontrol ettiniz mi?

    Str (Movable &) geçici bir nesne (s.Move() tarafından döndürülen) ile aradığınızdan!

    Bu, standartlara uygun değildir ve g ++ tarafından desteklenmez. MSVC tarafından desteklenmektedir! (MS buna bir özellik diyor ...).

    +0

    Haklısınız, g ++ altında derlenmeyecek, soruyu güncelledim. Muhtemelen farklı bir şey g ++ için yapılabilir, ama ben bir şey * benzer * bir yerde, tam olarak benim örnek uygulama değil, kullanılıp kullanılmadığını bilmek istiyorum. –