2011-08-23 22 views
7

में "आईडी" फ़ंक्शन this फ़ंक्शन से रैल्यू संदर्भों को वापस करने के संबंध में उत्तर मुझे सोचने लगा, मैंफ़ंक्शन C++ 0x में कैसे लिख सकता हूं।सी ++ 0x

असल में, मैं id चाहता हूं कि ऐसा कुछ भी न हो, एक ऐसा फ़ंक्शन जिसका प्रोग्राम पर कोई प्रभावशाली प्रभाव न हो।

#include <iostream> 

class X 
{ 
public: 
    X(std::string&& s) : s(std::move(s)) {}; 
    X(const std::string& s) : s(s) {}; 
    std::string s; 
    ~X() { std::cout << "Destroying: " << s << std::endl; } 
private: 
    X(const X&) {}; 
    X(X&&) {}; 
}; 

template <class T> 
T&& id(T&& x) { return static_cast<T&&>(x); } 

int main() 
{ 
    auto&& x1 = X("x1"); 
    std::cout << "Line 1" << std::endl; 
    auto&& x2 = id(X("x2")); 
    std::cout << "Line 2" << std::endl; 
} 

हालांकि, मुझे डर है कि इस मामले में, x2, एक झूलने संदर्भ के रूप में X("x2") नष्ट हो जाता है इससे पहले कि "लाइन 2" निष्पादित करता है:

मेरा पहला प्रयास के बाद है।

तो यहां, स्पष्ट रूप से id का एक प्रभावशाली प्रभाव है।

मैं सी ++ 0x में id फ़ंक्शन कैसे लिख सकता हूं, जो विशेष रूप से बिना किसी चाल/प्रति रचनाकारों के प्रकारों के लिए काम करता है।

+0

समस्या यह है कि एक फ़ंक्शन घोषणा यह नहीं बताती है कि लौटा संदर्भ अभी भी उसी ऑब्जेक्ट को संदर्भित करता है जो इसे पास कर दिया गया है। और यह निर्धारित करने के लिए कि यह वास्तव में क्या लौटाता है और अस्थायी जीवन का समय इस विश्लेषण पर निर्भर करता है, यह निर्धारित करने के लिए फ़ंक्शंस के कार्यान्वयन की जांच करने के लिए कंपाइलर्स को मजबूर करना उचित नहीं है। – sellibitze

उत्तर

7

आप नहीं कर सकते। एक नियम के रूप में, आपको उन कार्यों को नहीं लिखना चाहिए जो रावल संदर्भों को वापस करते हैं- और जैसा कि आपने सही तरीके से बताया है, आप अस्थायी लंबे समय तक जीवनकाल का विस्तार नहीं कर सकते हैं।

0

आप क्या करना चाहते क्या सही अग्रेषण कहा जाता है, और वहाँ एसटीएल कि यह करता है में एक समारोह है:

template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept 
{ 
    return static_cast<T&&>(t) 
} 
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept 
{ 
    return static_cast<T&&>(t) 
} 

आप remove_reference जरूरत संदर्भ पतन से बचने के लिए। और जब यह उपयोग कर, आप वस्तु आप अग्रेषित करना चाहते हैं, उसका प्रकार निर्दिष्ट करना होगा:

std::forward<X>(X("x2")); 
+1

मुझे विश्वास है कि यह एक पुराना विनिर्देश है और वर्तमान में मानक क्या नहीं है। इसके अलावा, यह * हल * समस्या हल नहीं करता है। – Puppy

0

प्रोग्रामिंग भाषाओं में अधिकांश चीजें पूरी तरह से नहीं है और पूरी तरह से मुक्त कर रहे हैं। जब तक आप संकलन-समय केवल कोड लिख रहे हों, एक पहचान फ़ंक्शन लिखना मुफ़्त होने की संभावना नहीं है।

के अपने कोड थोड़ा rework करते हैं:

#include <algorithm> 
#include <iostream> 

template <typename T> 
T id1(T&& t) 
{ 
    return t; 
} 

template <typename T> 
T id2(T&& t) 
{ 
    return std::move(t); 
} 


class X 
{ 
public: 
    X() 
    { output0("Xdef"); } 
    X(std::string const& s) : label_(s) 
    { output1("Xstr",s); } 
    X(X const& x) : label_(x.label_) 
    { output1("Xcopy", x); } 
    X(X&& x) : label_(std::move(x.label_)) 
    { output1("Xmove", x); } 

    X& operator =(X const& x) 
    { 
    output1("operator =copy", x); 
    label_ = x.label_; 
    return *this; 
    } 

    X& operator =(X&& x) 
    { 
    using std::swap; 
    output1("operator =move", x); 
    swap(label_, x.label_); 
    return *this; 
    } 

    ~X() 
    { output0("~X"); } 

private: 
    void output_id() const 
    { 
    std::cout << this << '[' << label_ << "]"; 
    } 

    void output0(std::string const& name) const 
    { 
    output_id(); 
    std::cout << ": " << name << "()" << std::endl; 
    } 

    void output1(std::string const& name, std::string const& str) const 
    { 
    output_id(); 
    std::cout 
     << ": " << name 
     << "(\"" << str 
     << "\")" << std::endl; 
    } 

    void output1(std::string const& name, X const& arg) const 
    { 
    output_id(); 
    std::cout << ": " << name << '('; 
    arg.output_id(); 
    std::cout << ')' << std::endl; 
    } 

    std::string label_; 
}; 

int main() 
{ 
    { 
    std::cout << "CASE A:\n"; 
    auto x = X("x1"); 
    } 
    std::cout << "\n"; 
    { 
    std::cout << "CASE B:\n"; 
    auto x = id1(X("x2")); 
    } 
    std::cout << "\n"; 
    { 
    std::cout << "CASE C:\n"; 
    auto x = id2(X("x3")); 
    } 
    std::cout << "\n"; 
    { 
    std::cout << "CASE D:\n"; 
    X x = id1(X("x4")); 
    } 
    std::cout << "\n"; 
    { 
    std::cout << "CASE E:\n"; 
    X x = id2(X("x5")); 
    } 
}  

और जब चलाने यह (एक जीसीसी v4.8 स्नैपशॉट का प्रयोग करके) आउटपुट:

$ ./a.out 
CASE A: 
0x7fff411fc530[x1]: Xstr("x1") 
0x7fff411fc530[x1]: ~X() 

CASE B: 
0x7fff411fc540[x2]: Xstr("x2") 
0x7fff411fc520[x2]: Xcopy(0x7fff411fc540[x2]) 
0x7fff411fc540[x2]: ~X() 
0x7fff411fc520[x2]: ~X() 

CASE C: 
0x7fff411fc540[x3]: Xstr("x3") 
0x7fff411fc520[x3]: Xmove(0x7fff411fc540[]) 
0x7fff411fc540[]: ~X() 
0x7fff411fc520[x3]: ~X() 

CASE D: 
0x7fff411fc540[x4]: Xstr("x4") 
0x7fff411fc520[x4]: Xcopy(0x7fff411fc540[x4]) 
0x7fff411fc540[x4]: ~X() 
0x7fff411fc520[x4]: ~X() 

CASE E: 
0x7fff411fc540[x5]: Xstr("x5") 
0x7fff411fc520[x5]: Xmove(0x7fff411fc540[]) 
0x7fff411fc540[]: ~X() 
0x7fff411fc520[x5]: ~X() 
$ 

प्रकरण एक बस निर्माता का आह्वान एक्स के लिए = इस उदाहरण में = के दाईं ओर दाईं ओर जाने के बराबर है, यानी, यह असाइनमेंट नहीं है।

केस बी id1() को आमंत्रित करता है जो इसकी वापसी तर्क को स्थानांतरित नहीं करता है। चूंकि लौटाया गया मूल्य आईडी() के कॉल स्टैक पर परिभाषित नहीं किया गया था और मान एक लवल्यू (एक रैवल्यू धारण करना) है, यह स्वचालित रूप से वापसी पर नहीं ले जाया गया था और इसलिए इसकी प्रतिलिपि बनाई गई थी।

केस सी id2() को आमंत्रित करता है जो बदले में चालक कन्स्ट्रक्टर का आह्वान करता है।

मामले डी और ई क्रमशः मामले बी और सी के समान हैं, सिवाय इसके कि auto का उपयोग नहीं किया जाता है यदि आप इस बारे में संदेह रखते हैं।

मूव को अनुकूलित प्रतियों के रूप में देखा जाना चाहिए और सबसे बुरे मामले में प्रतियों के रूप में खराब होना चाहिए (हालांकि वे अक्सर बेहतर होते हैं)।यहां तक ​​कि एक इष्टतम चाल की लागत भी होती है (उदाहरण के लिए, कुछ डेटा (आमतौर पर) को एक स्टैक फ्रेम से दूसरे में कॉपी करना)। रन-टाइम कोड में एकमात्र तरीका प्रतियां/चाल पूरी तरह से टाल जाती हैं जब रिटर्न वैल्यू ऑप्टिमाइज़ेशन और कॉपी एलिसन कंपाइलर के उपयोग के लिए योग्य होते हैं।