मैं एक फ़ंक्शन में std :: unique_ptr कैसे पास कर सकता हूं


101

मैं std::unique_ptrफंक्शन में कैसे पास हो सकता हूं ? चलो कहते हैं कि मेरे पास निम्न वर्ग है:

class A
{
public:
    A(int val)
    {
        _val = val;
    }

    int GetVal() { return _val; }
private:
    int _val;
};

निम्नलिखित संकलन नहीं है:

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);

    return 0;
}

मैं std::unique_ptrकिसी फ़ंक्शन में पास क्यों नहीं कर सकता ? निश्चित रूप से यह निर्माण का प्राथमिक उद्देश्य है? या C ++ कमेटी ने मुझे कच्चे सी-स्टाइल पॉइंटर्स पर वापस जाने का इरादा किया और इसे इस तरह से पास किया:

MyFunc(&(*ptr)); 

और सबसे अजीब, यह क्यों इसे पारित करने का एक ठीक तरीका है? यह बहुत ही असंगत लगता है:

MyFunc(unique_ptr<A>(new A(1234)));

7
कच्चे सी-स्टाइल पॉइंटर्स पर "पीछे गिरने" के साथ कुछ भी गलत नहीं है जब तक कि वे गैर-स्वामित्व वाले कच्चे पॉइंटर्स हैं। आप 'ptr.get ()' लिखना पसंद कर सकते हैं। यद्यपि, यदि आपको अशक्तता की आवश्यकता नहीं है, तो एक संदर्भ को प्राथमिकता दी जाएगी।
क्रिस ड्रू

जवाबों:


148

यहां मूल रूप से दो विकल्प हैं:

संदर्भ द्वारा स्मार्ट पॉइंटर पास करें

void MyFunc(unique_ptr<A> & arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);
}

फ़ंक्शन सूचक में स्मार्ट पॉइंटर को स्थानांतरित करें

ध्यान दें कि इस मामले में, जोर पकड़ जाएगा!

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(move(ptr));
    assert(ptr == nullptr)
}

@VermillionAzure: जिस फीचर का आप जिक्र कर रहे हैं, उसे आम तौर पर नॉनकोप्लेबल कहा जाता है, अनोखा नहीं।
बिल लिंच

1
धन्यवाद। इस मामले में मैं एक उदाहरण बनाना चाहता था, उस पर कुछ कार्रवाई करना और फिर किसी और को स्वामित्व देना बंद कर देता हूं, जो आगे बढ़ता है ()।
user3690202

7
unique_ptrयदि फ़ंक्शन इसे से स्थानांतरित कर सकता है या नहीं कर सकता है, तो आपको केवल संदर्भ द्वारा पास करना चाहिए । और फिर यह एक संदर्भ होना चाहिए। किसी वस्तु को उसके स्वामित्व शब्दार्थ के बारे में कुछ भी आवश्यकता के बिना देखने के लिए, जैसे संदर्भ का उपयोग करें A const&या A&
पोटाटोसवेटर

14
CppCon 2014 पर हर्ब सुटर्स से बात करें। वह अनूठे_ptr <> के संदर्भ देने के लिए दृढ़ता से हतोत्साहित करता है। सार यह है, कि जब आप स्वामित्व के साथ व्यवहार करते हैं, तो आपको यूनीक_प्ट्र </ या साझा_प्ट्र <> जैसे स्मार्ट पॉइंटर्स का उपयोग करना चाहिए। यहां देखें www.youtube.com/watch?v=xnqTKD8uD64 यहां आप स्लाइड्स देख सकते हैं github.com/CppCon/CppCon2014/tree/master/Presentations/…
schorsch -76

2
@ फुरीर: यह दिखाने का एक तरीका है कि ptrइस कदम के बाद क्या मूल्य है।
बिल लिंच

28

आप इसे मूल्य से पास कर रहे हैं, जिसका अर्थ है एक प्रतिलिपि बनाना। यह बहुत अनूठा नहीं होगा, यह होगा?

आप मान को स्थानांतरित कर सकते हैं, लेकिन इसका तात्पर्य है कि वस्तु का स्वामित्व और कार्य के लिए उसके जीवनकाल का नियंत्रण।

यदि ऑब्जेक्ट का जीवनकाल MyFunc को कॉल के जीवनकाल में मौजूद होने की गारंटी है, तो बस एक कच्चे सूचक को पास करें ptr.get()


17

मैं unique_ptrकिसी फ़ंक्शन में पास क्यों नहीं कर सकता ?

आप ऐसा नहीं कर सकते क्योंकि unique_ptrइसमें एक मूव कंस्ट्रक्टर है लेकिन कॉपी कंस्ट्रक्टर नहीं है। मानक के अनुसार, जब एक मूव कंस्ट्रक्टर को परिभाषित किया जाता है, लेकिन एक कॉपी कंस्ट्रक्टर को परिभाषित नहीं किया जाता है, तो कॉपी कंस्ट्रक्टर को हटा दिया जाता है।

12.8 क्लास ऑब्जेक्ट्स को कॉपी करना और ले जाना

...

7 यदि कक्षा की परिभाषा स्पष्ट रूप से कॉपी निर्माता की घोषणा नहीं करती है, तो एक को स्पष्ट रूप से घोषित किया जाता है। यदि वर्ग परिभाषा एक चाल निर्माणकर्ता या चाल असाइनमेंट ऑपरेटर की घोषणा करती है, तो अंतर्निहित रूप से घोषित प्रतिलिपि निर्माता को हटाए जाने के रूप में परिभाषित किया गया है;

आप unique_ptrफ़ंक्शन का उपयोग करके पास कर सकते हैं :

void MyFunc(std::unique_ptr<A>& arg)
{
    cout << arg->GetVal() << endl;
}

और इसे अपने जैसे उपयोग करें:

या

void MyFunc(std::unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

और इसका उपयोग करें:

std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));

महत्वपूर्ण लेख

कृपया ध्यान दें कि यदि आप दूसरी विधि का उपयोग करते हैं, ptrतो std::move(ptr)रिटर्न के लिए कॉल के बाद सूचक का स्वामित्व नहीं है ।

void MyFunc(std::unique_ptr<A>&& arg)void MyFunc(std::unique_ptr<A>& arg)दोनों संदर्भों के रूप में एक ही प्रभाव होगा ।

पहले मामले में, ptrअभी भी कॉल के बाद सूचक का स्वामित्व है MyFunc


5

जैसा कि MyFuncस्वामित्व नहीं लेता है, यह बेहतर होगा:

void MyFunc(const A* arg)
{
    assert(arg != nullptr); // or throw ?
    cout << arg->GetVal() << endl;
}

या और अच्छा

void MyFunc(const A& arg)
{
    cout << arg.GetVal() << endl;
}

यदि आप वास्तव में स्वामित्व लेना चाहते हैं, तो आपको अपना संसाधन स्थानांतरित करना होगा:

std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));

या सीधे आर-मान संदर्भ पास करें:

MyFunc(std::make_unique<A>(1234));

std::unique_ptr केवल एक ही मालिक होने के लिए गारंटी देने के उद्देश्य से प्रतिलिपि नहीं है।


यह उत्तर याद आ रहा है कि MyFunc को कॉल आपके पहले दो मामलों के लिए कैसा दिखता है। सुनिश्चित नहीं हैं कि आप उपयोग कर रहे हैं ptr.get()या केवल ptrफ़ंक्शन में जा रहे हैं?
taylorstine

MyFuncएक आर-मूल्य संदर्भ पास करने के लिए इरादा हस्ताक्षर क्या है ?
जेम्स हिर्शोर्न

@JamesHirschorn: void MyFunc(A&& arg)r-value reference लेता है ...
Jarod42

@ Jarod42 यही मैंने अनुमान लगाया है, लेकिन साथ में typedef int A[], MyFunc(std::make_unique<A>(N))कंपाइलर त्रुटि देता है: त्रुटि: प्रकार के संदर्भ में 'आर' (&&) [] टाइप के संदर्भ में अमान्य इनिशियलाइज़ेशन 'std :: _ MakeUniq <int []> ::__ _ सरणी' { उर्फ 'std :: unique_ptr <int [], std :: default_delete <int []>>'> g++ -std=gnu++11हाल ही में पर्याप्त है?
जेम्स हिर्सचोर्न

@ Jarod42 मैंने ideone के साथ C ++ 14 के लिए विफलता की पुष्टि की: ideone.com/YRRT24
जेम्स हिर्स्चोर्न

4

मैं unique_ptrकिसी फ़ंक्शन में पास क्यों नहीं कर सकता ?

आप कर सकते हैं, लेकिन कॉपी std::unique_ptr<>से नहीं - क्योंकि कॉपी-कंस्ट्रक्टिव नहीं है।

निश्चित रूप से यह निर्माण का प्राथमिक उद्देश्य है?

अन्य बातों के अलावा, अद्वितीय स्वामित्व (जैसा कि विरोध किया गया है ) std::unique_ptr<>को असमान रूप से चिह्नित करने के लिए डिज़ाइन किया गया है ।std::shared_ptr<>

और सबसे अजीब, यह क्यों इसे पारित करने का एक ठीक तरीका है?

क्योंकि उस मामले में, कोई कॉपी-कंस्ट्रक्शन नहीं है।


आपके उत्तर के लिए धन्यवाद। बस ब्याज से बाहर, आप बता सकते हैं कि इसे पारित करने का आखिरी तरीका कॉपी कंस्ट्रक्टर का उपयोग क्यों नहीं कर रहा है? मैंने सोचा होगा कि यूनिक_प्रटर के कंस्ट्रक्टर का उपयोग स्टैक पर एक उदाहरण उत्पन्न करेगा, जिसे कॉपी कंस्ट्रक्टर का उपयोग करके MyFunc () के लिए तर्कों में कॉपी किया जाएगा? हालांकि मैं स्वीकार करता हूं कि मेरा स्मरण इस क्षेत्र में थोड़ा अस्पष्ट है।
user3690202

2
जैसा कि यह एक प्रतिद्वंद्विता है, इसके बजाय कदम-निर्माता को बुलाया जाता है। हालांकि आपके कंपाइलर निश्चित रूप से इसे वैसे भी ऑप्टिमाइज़ करेंगे।
नीलकंठ

0

चूंकि unique_ptrअद्वितीय स्वामित्व के लिए है, यदि आप इसे तर्क कोशिश के रूप में पारित करना चाहते हैं

MyFunc(move(ptr));

लेकिन उसके बाद की स्थिति ptrमें mainहो जाएगा nullptr


4
"अपरिभाषित होगा" - नहीं, यह अशक्त unique_ptrहोगा , या बल्कि बेकार होगा।
टीसी

0

std::unique_ptr<T>किसी फ़ंक्शन के मान के रूप में पास करना काम नहीं कर रहा है, क्योंकि जैसा कि आप लोग उल्लेख करते हैं, unique_ptrप्रतिलिपि योग्य नहीं है।

इस बारे में क्या?

std::unique_ptr<T> getSomething()
{
   auto ptr = std::make_unique<T>();
   return ptr;
}

यह कोड काम कर रहा है


अगर वह कोड काम करता है तो मेरा अनुमान होगा कि यह यूनिक_प्रटर की नकल नहीं कर रहा है, बल्कि वास्तव में इसे स्थानांतरित करने के लिए शब्दार्थ का उपयोग कर रहा है।
user3690202

रिटर्न वैल्यू ऑप्टिमाइज़ेशन (
आरवीओ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.