लैम्ब्डा में कब्जा हटो


157

मैं C ++ 11 लैम्ब्डा में मूव (जिसे रेवल्यू रेफरेंस के रूप में भी जाना जाता है) पर कब्जा कैसे करूं?

मैं कुछ इस तरह लिखने की कोशिश कर रहा हूं:

std::unique_ptr<int> myPointer(new int);

std::function<void(void)> example = [std::move(myPointer)]{
   *myPointer = 4;
};

जवाबों:


163

C ++ 14 में सामान्यीकृत लैम्ब्डा कैप्चर

C ++ 14 में हमारे पास तथाकथित सामान्यीकृत लैम्ब्डा कैप्चर होगा । यह चाल को पकड़ने में सक्षम बनाता है। निम्नलिखित C ++ 14 में कानूनी कोड होगा:

using namespace std;

// a unique_ptr is move-only
auto u = make_unique<some_type>( some, parameters );  

// move the unique_ptr into the lambda
go.run( [ u{move(u)} ] { do_something_with( u ); } ); 

लेकिन यह इस अर्थ में बहुत अधिक सामान्य है कि कैप्चर किए गए चर को किसी भी चीज़ के साथ आरंभ किया जा सकता है:

auto lambda = [value = 0] mutable { return ++value; };

C ++ 11 में यह अभी तक संभव नहीं है, लेकिन कुछ चालों के साथ जिसमें सहायक प्रकार शामिल हैं। सौभाग्य से, क्लैंग 3.4 कंपाइलर पहले से ही इस भयानक विशेषता को लागू करता है। संकलक दिसंबर 2013 या जनवरी 2014 में जारी किया जाएगा, अगर हालिया रिलीज़ गति रखी जाएगी।

अद्यतन: बजना 3.4 संकलक को कहा सुविधा के साथ 6 जनवरी 2014 को जारी किया गया।

चाल पकड़ने के लिए एक समाधान

यहां एक सहायक फ़ंक्शन का कार्यान्वयन है make_rrefजो कृत्रिम चाल को पकड़ने में मदद करता है

#include <cassert>
#include <memory>
#include <utility>

template <typename T>
struct rref_impl
{
    rref_impl() = delete;
    rref_impl( T && x ) : x{std::move(x)} {}
    rref_impl( rref_impl & other )
        : x{std::move(other.x)}, isCopied{true}
    {
        assert( other.isCopied == false );
    }
    rref_impl( rref_impl && other )
        : x{std::move(other.x)}, isCopied{std::move(other.isCopied)}
    {
    }
    rref_impl & operator=( rref_impl other ) = delete;
    T && move()
    {
        return std::move(x);
    }

private:
    T x;
    bool isCopied = false;
};

template<typename T> rref_impl<T> make_rref( T && x )
{
    return rref_impl<T>{ std::move(x) };
}

और यहाँ उस फ़ंक्शन के लिए एक परीक्षण मामला है जो मेरे gcc 4.7.3 पर सफलतापूर्वक चला।

int main()
{
    std::unique_ptr<int> p{new int(0)};
    auto rref = make_rref( std::move(p) );
    auto lambda =
        [rref]() mutable -> std::unique_ptr<int> { return rref.move(); };
    assert(  lambda() );
    assert( !lambda() );
}

यहाँ दोष यह है कि lambdaप्रतिलिपि करने योग्य है और जब rref_implएक रनटाइम बग के लिए विफल रहता है की प्रतिलिपि निर्माता में जोर की नकल की । निम्नलिखित एक बेहतर और भी अधिक सामान्य समाधान हो सकता है क्योंकि संकलक त्रुटि को पकड़ लेगा।

C ++ 11 में सामान्यीकृत लैम्ब्डा कैप्चर का अनुकरण

यहाँ एक और विचार है, सामान्यीकृत लैम्ब्डा कैप्चर को कैसे लागू किया जाए। फ़ंक्शन का उपयोग capture()(जिसका कार्यान्वयन आगे पाया गया है) निम्नानुसार है:

#include <cassert>
#include <memory>

int main()
{
    std::unique_ptr<int> p{new int(0)};
    auto lambda = capture( std::move(p),
        []( std::unique_ptr<int> & p ) { return std::move(p); } );
    assert(  lambda() );
    assert( !lambda() );
}

यहाँ lambdaएक फ़नकार ऑब्जेक्ट (लगभग एक वास्तविक लंबोदर) है, जिस पर कब्जा कर लिया std::move(p)गया है capture()। का दूसरा तर्क captureएक लंबोदर है जो कैप्चर किए गए चर को एक तर्क के रूप में लेता है। जब lambdaइसे एक फ़ंक्शन ऑब्जेक्ट के रूप में उपयोग किया जाता है, तो इसे पारित किए जाने वाले सभी तर्कों को कैप्चर किए गए चर के बाद तर्क के रूप में आंतरिक लंबो को भेज दिया जाएगा। (हमारे मामले में आगे कोई तर्क नहीं दिया जाना है)। अनिवार्य रूप से, पिछले समाधान के समान ही होता है। यहां बताया गया captureहै:

#include <utility>

template <typename T, typename F>
class capture_impl
{
    T x;
    F f;
public:
    capture_impl( T && x, F && f )
        : x{std::forward<T>(x)}, f{std::forward<F>(f)}
    {}

    template <typename ...Ts> auto operator()( Ts&&...args )
        -> decltype(f( x, std::forward<Ts>(args)... ))
    {
        return f( x, std::forward<Ts>(args)... );
    }

    template <typename ...Ts> auto operator()( Ts&&...args ) const
        -> decltype(f( x, std::forward<Ts>(args)... ))
    {
        return f( x, std::forward<Ts>(args)... );
    }
};

template <typename T, typename F>
capture_impl<T,F> capture( T && x, F && f )
{
    return capture_impl<T,F>(
        std::forward<T>(x), std::forward<F>(f) );
}

यह दूसरा समाधान भी क्लीनर है, क्योंकि यह लैम्ब्डा की प्रतिलिपि बनाने में अक्षम करता है, यदि कैप्चर किया गया प्रकार कॉपी करने योग्य नहीं है। पहले समाधान में जिसे केवल रनटाइम पर चेक किया जा सकता है a assert()


मैं इसे G ++ - 4.8 -std = c ++ 11 के साथ लंबे समय से उपयोग कर रहा हूं, और मुझे लगा कि यह C ++ 11 फीचर है। अब मैं इस का उपयोग कर रहा हूँ और अचानक एहसास हुआ कि यह एक C ++ 14 फीचर है ... मुझे क्या करना चाहिए !!
RnMss

@ RnMss आपको किस विशेषता से मतलब है? सामान्यीकृत लैम्ब्डा पर कब्जा?
राल्फ टंडेट्ज़की

@RalphTandetzky मुझे ऐसा लगता है, मैंने अभी-अभी जाँच की है और XCode के साथ बंधे क्लैंग का संस्करण भी समर्थन करता प्रतीत होता है! यह एक चेतावनी देता है कि यह C ++ 1y एक्सटेंशन है लेकिन यह काम करता है।
क्रिस्टोफर तारिणी

@RnMss या तो moveCaptureउन्हें तर्क के रूप में पारित करने के लिए एक आवरण का उपयोग करें (यह विधि ऊपर और कैपन'प्रोटो में, प्रोटोबफ़्स के निर्माता द्वारा एक पुस्तकालय) का उपयोग किया जाता है या बस यह स्वीकार करें कि आपको ऐसे कंपाइलरों की आवश्यकता है जो इसका समर्थन करते हैं:
क्रिस्टोफर टर्कीनी

9
नहीं, यह वास्तव में एक ही बात नहीं है। उदाहरण: आप एक लैंबड़ा के साथ एक धागा स्पॉन करना चाहते हैं जो अद्वितीय सूचक को स्थानांतरित करता है। स्पैनिंग फ़ंक्शन संभवतः वापस आ सकता है और फ़नकार के निष्पादित होने से पहले अनूठे_ptr दायरे से बाहर चला जाता है। इसलिए, आपके पास एक Unique_ptr के लिए एक झूलने वाला संदर्भ है। अपरिभाषित व्यवहार-भूमि में आपका स्वागत है।
राल्फ टंडेट्ज़की

76

तुम भी std::bindकब्जा करने के लिए उपयोग कर सकते हैं unique_ptr:

std::function<void()> f = std::bind(
                              [] (std::unique_ptr<int>& p) { *p=4; },
                              std::move(myPointer)
                          );

2
इसे पोस्ट करने के लिए आपका धन्यवाद!
mmocny

4
क्या आपने जाँच की है, यदि कोड संकलित है? यह मेरे लिए ऐसा नहीं लगता है, क्योंकि पहले चर नाम गायब है और दूसरी बात यह है कि एक unique_ptrसंदर्भ संदर्भ एक के लिए बाध्य नहीं कर सकता है int *
राल्फ टांडेट्स्की

7
ध्यान दें कि विजुअल स्टूडियो 2013 में, एक std :: bind to a std :: function में कनवर्ट करने के बाद भी इसमें सभी बाध्य चर ( myPointerइस मामले में) की प्रतिलिपि बनती है । इसलिए उपरोक्त कोड VS2013 में संकलित नहीं है। यह जीसीसी 4.8 में हालांकि ठीक है।
एलन

22

आप std::bindइस तरह से जो भी उपयोग करना चाहते हैं , उसे प्राप्त कर सकते हैं :

std::unique_ptr<int> myPointer(new int{42});

auto lambda = std::bind([](std::unique_ptr<int>& myPointerArg){
    *myPointerArg = 4;
     myPointerArg.reset(new int{237});
}, std::move(myPointer));

यहाँ ट्रिक यह है कि कैप्चर लिस्ट में आपकी मूव-ओनली ऑब्जेक्ट को कैप्चर करने के बजाय, हम इसे एक तर्क बनाते हैं और फिर std::bindइसे गायब करने के लिए आंशिक एप्लिकेशन का उपयोग करते हैं । ध्यान दें कि लैम्ब्डा इसे संदर्भ द्वारा लेता है , क्योंकि यह वास्तव में बाइंड ऑब्जेक्ट में संग्रहीत है। मैंने वह कोड भी जोड़ा है जो वास्तविक चल वस्तु पर लिखता है, क्योंकि वह कुछ ऐसा है जो आप करना चाहते हैं।

C ++ 14 में, आप इस कोड के साथ समान छोरों को प्राप्त करने के लिए सामान्यीकृत लैम्ब्डा कैप्चर का उपयोग कर सकते हैं:

std::unique_ptr<int> myPointer(new int{42});

auto lambda = [myPointerCapture = std::move(myPointer)]() mutable {
    *myPointerCapture = 56;
    myPointerCapture.reset(new int{237});
};

लेकिन यह कोड आपको C ++ 11 के माध्यम से कुछ भी नहीं खरीदता है std::bind। (कुछ परिस्थितियां हैं जहां सामान्यीकृत लैम्ब्डा कैप्चर अधिक शक्तिशाली है, लेकिन इस मामले में नहीं।)

अब सिर्फ एक समस्या है; आप इस फ़ंक्शन को एक में रखना चाहते थे std::function, लेकिन उस वर्ग के लिए आवश्यक है कि फ़ंक्शन CopyConstructible हो , लेकिन ऐसा नहीं है, यह केवल MoveConstructible है क्योंकि यह एक ऐसा स्टोर है std::unique_ptrजो CopyConstructible नहीं है ।

आप रैपर वर्ग और अप्रत्यक्ष स्तर के दूसरे स्तर पर इस मुद्दे पर काम कर सकते हैं, लेकिन शायद आपको इसकी बिल्कुल भी जरूरत नहीं है std::function। अपनी आवश्यकताओं के आधार पर, आप उपयोग करने में सक्षम हो सकते हैं std::packaged_task; यह उसी तरह काम करेगा std::function, लेकिन इसके लिए फ़ंक्शन को प्रतिलिपि योग्य होने की आवश्यकता नहीं है, केवल चल (इसी तरह, std::packaged_taskकेवल चल) है। नकारात्मक पक्ष यह है कि क्योंकि यह एसटीडी :: भविष्य के साथ संयोजन के रूप में उपयोग करने का इरादा है, आप इसे केवल एक बार कॉल कर सकते हैं।

यहाँ एक छोटा कार्यक्रम है जो इन सभी अवधारणाओं को दर्शाता है।

#include <functional>   // for std::bind
#include <memory>       // for std::unique_ptr
#include <utility>      // for std::move
#include <future>       // for std::packaged_task
#include <iostream>     // printing
#include <type_traits>  // for std::result_of
#include <cstddef>

void showPtr(const char* name, const std::unique_ptr<size_t>& ptr)
{
    std::cout << "- &" << name << " = " << &ptr << ", " << name << ".get() = "
              << ptr.get();
    if (ptr)
        std::cout << ", *" << name << " = " << *ptr;
    std::cout << std::endl;
}

// If you must use std::function, but your function is MoveConstructable
// but not CopyConstructable, you can wrap it in a shared pointer.
template <typename F>
class shared_function : public std::shared_ptr<F> {
public:
    using std::shared_ptr<F>::shared_ptr;

    template <typename ...Args>
    auto operator()(Args&&...args) const
        -> typename std::result_of<F(Args...)>::type
    {
        return (*(this->get()))(std::forward<Args>(args)...);
    }
};

template <typename F>
shared_function<F> make_shared_fn(F&& f)
{
    return shared_function<F>{
        new typename std::remove_reference<F>::type{std::forward<F>(f)}};
}


int main()
{
    std::unique_ptr<size_t> myPointer(new size_t{42});
    showPtr("myPointer", myPointer);
    std::cout << "Creating lambda\n";

#if __cplusplus == 201103L // C++ 11

    // Use std::bind
    auto lambda = std::bind([](std::unique_ptr<size_t>& myPointerArg){
        showPtr("myPointerArg", myPointerArg);  
        *myPointerArg *= 56;                    // Reads our movable thing
        showPtr("myPointerArg", myPointerArg);
        myPointerArg.reset(new size_t{*myPointerArg * 237}); // Writes it
        showPtr("myPointerArg", myPointerArg);
    }, std::move(myPointer));

#elif __cplusplus > 201103L // C++14

    // Use generalized capture
    auto lambda = [myPointerCapture = std::move(myPointer)]() mutable {
        showPtr("myPointerCapture", myPointerCapture);
        *myPointerCapture *= 56;
        showPtr("myPointerCapture", myPointerCapture);
        myPointerCapture.reset(new size_t{*myPointerCapture * 237});
        showPtr("myPointerCapture", myPointerCapture);
    };

#else
    #error We need C++11
#endif

    showPtr("myPointer", myPointer);
    std::cout << "#1: lambda()\n";
    lambda();
    std::cout << "#2: lambda()\n";
    lambda();
    std::cout << "#3: lambda()\n";
    lambda();

#if ONLY_NEED_TO_CALL_ONCE
    // In some situations, std::packaged_task is an alternative to
    // std::function, e.g., if you only plan to call it once.  Otherwise
    // you need to write your own wrapper to handle move-only function.
    std::cout << "Moving to std::packaged_task\n";
    std::packaged_task<void()> f{std::move(lambda)};
    std::cout << "#4: f()\n";
    f();
#else
    // Otherwise, we need to turn our move-only function into one that can
    // be copied freely.  There is no guarantee that it'll only be copied
    // once, so we resort to using a shared pointer.
    std::cout << "Moving to std::function\n";
    std::function<void()> f{make_shared_fn(std::move(lambda))};
    std::cout << "#4: f()\n";
    f();
    std::cout << "#5: f()\n";
    f();
    std::cout << "#6: f()\n";
    f();
#endif
}

मैंने कॉलिरु पर एक उपरोक्त कार्यक्रम रखा है , ताकि आप कोड के साथ चला सकें और खेल सकें।

यहां जानिए कुछ खास आउटपुट ...

- &myPointer = 0xbfffe5c0, myPointer.get() = 0x7ae3cfd0, *myPointer = 42
Creating lambda
- &myPointer = 0xbfffe5c0, myPointer.get() = 0x0
#1: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 42
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 2352
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 557424
#2: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 557424
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 31215744
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 3103164032
#3: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 3103164032
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 1978493952
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
Moving to std::function
#4: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3436650496
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608
#5: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2967666688
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3257335808
#6: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3257335808
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 2022178816
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2515009536

आपको यह देखने के लिए मिलता है कि ढेर के स्थान पुन: उपयोग किए जा रहे हैं, यह दर्शाता है कि यह std::unique_ptrठीक से काम कर रहा है। आप यह भी देखते हैं कि जब हम किसी रैपर में खाना खिलाते हैं तो फंक्शन खुद ही घूम जाता है std::function

यदि हम उपयोग करने के लिए स्विच करते हैं std::packaged_task, तो यह अंतिम भाग बन जाता है

Moving to std::packaged_task
#4: f()
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3436650496
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608

इसलिए हम देखते हैं कि फ़ंक्शन को स्थानांतरित कर दिया गया है, लेकिन ढेर पर स्थानांतरित होने के बजाय, यह std::packaged_taskस्टैक पर है।

उम्मीद है की यह मदद करेगा!


4

देर से, लेकिन कुछ लोग (मेरे सहित) अभी भी c ++ 11 पर अटके हुए हैं:

सच कहूं तो, मैं वास्तव में किसी भी पोस्ट किए गए समाधान को पसंद नहीं करता हूं। मुझे यकीन है कि वे काम करेंगे, लेकिन उन्हें अतिरिक्त सामान और / या क्रिप्टोकरेंसी std::bindसिंटैक्स की बहुत आवश्यकता है ... और मुझे नहीं लगता कि यह इस तरह के अस्थायी समाधान के लिए प्रयास के लायक है, जिसे सी ++ में अपग्रेड करते समय वैसे भी रिफलेक्ट किया जाएगा। = 14. तो मुझे लगता है कि सबसे अच्छा समाधान पूरी तरह से c ++ 11 के लिए कब्जा करने से बचने के लिए है।

आमतौर पर सबसे सरल और सबसे अच्छा पठनीय समाधान का उपयोग करना है std::shared_ptr, जो प्रतिलिपि बनाने योग्य हैं और इसलिए यह कदम पूरी तरह से परिहार्य है। नकारात्मक पक्ष यह है कि यह थोड़ा कम कुशल है, लेकिन कई मामलों में दक्षता इतनी महत्वपूर्ण नहीं है।

// myPointer could be a parameter or something
std::unique_ptr<int> myPointer(new int);

// convert/move the unique ptr into a shared ptr
std::shared_ptr<int> mySharedPointer( std::move(myPointer) );

std::function<void(void)> = [mySharedPointer](){
   *mySharedPointer = 4;
};

// at end of scope the original mySharedPointer is destroyed,
// but the copy still lives in the lambda capture.

यदि बहुत दुर्लभ मामला होता है, तो यह वास्तव moveमें सूचक के लिए अनिवार्य है (जैसे कि आप स्पष्ट रूप से लंबे समय तक हटाने की वजह से एक अलग थ्रेड में एक संकेतक को हटाना चाहते हैं, या प्रदर्शन बिल्कुल महत्वपूर्ण है), यह बहुत ही एकमात्र मामला है जहां मैं अभी भी उपयोग करता हूं कच्चे संकेत c ++ 11 में। ये निश्चित रूप से प्रतिलिपि योग्य भी हैं।

आमतौर पर मैं इन दुर्लभ मामलों को एक के साथ चिह्नित करता हूं //FIXME:ताकि यह सुनिश्चित हो सके कि यह एक बार c ++ 14 में अपग्रेड हो गया है।

// myPointer could be a parameter or something
std::unique_ptr<int> myPointer(new int);

//FIXME:c++11 upgrade to new move capture on c++>=14

// "move" the pointer into a raw pointer
int* myRawPointer = myPointer.release();

// capture the raw pointer as a copy.
std::function<void(void)> = [myRawPointer](){
   std::unique_ptr<int> capturedPointer(myRawPointer);
   *capturedPointer = 4;
};

// ensure that the pointer's value is not accessible anymore after capturing
myRawPointer = nullptr;

हाँ, कच्चे संकेत इन दिनों (और बिना किसी कारण के) पर बहुत अधिक डूब जाते हैं, लेकिन मैं वास्तव में इन दुर्लभ (और अस्थायी!) मामलों में सोचता हूं कि वे सबसे अच्छा समाधान हैं।


धन्यवाद, C ++ 14 और अन्य समाधानों का उपयोग करना अच्छा था। मेरा दिन बचाया!
योव स्टर्नबर्ग

1

मैं इन जवाबों को देख रहा था, लेकिन मुझे पढ़ना और समझना मुश्किल लग रहा था। इसलिए मैंने जो किया वह एक ऐसा वर्ग था जो नकल के बजाय आगे बढ़ता गया। इस तरह, यह स्पष्ट है कि यह क्या कर रहा है।

#include <iostream>
#include <memory>
#include <utility>
#include <type_traits>
#include <functional>

namespace detail
{
    enum selection_enabler { enabled };
}

#define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), ::detail::selection_enabler> \
                          = ::detail::enabled

// This allows forwarding an object using the copy constructor
template <typename T>
struct move_with_copy_ctor
{
    // forwarding constructor
    template <typename T2
        // Disable constructor for it's own type, since it would
        // conflict with the copy constructor.
        , ENABLE_IF(
            !std::is_same<std::remove_reference_t<T2>, move_with_copy_ctor>::value
        )
    >
    move_with_copy_ctor(T2&& object)
        : wrapped_object(std::forward<T2>(object))
    {
    }

    // move object to wrapped_object
    move_with_copy_ctor(T&& object)
        : wrapped_object(std::move(object))
    {
    }

    // Copy constructor being used as move constructor.
    move_with_copy_ctor(move_with_copy_ctor const& object)
    {
        std::swap(wrapped_object, const_cast<move_with_copy_ctor&>(object).wrapped_object);
    }

    // access to wrapped object
    T& operator()() { return wrapped_object; }

private:
    T wrapped_object;
};


template <typename T>
move_with_copy_ctor<T> make_movable(T&& object)
{
    return{ std::forward<T>(object) };
}

auto fn1()
{
    std::unique_ptr<int, std::function<void(int*)>> x(new int(1)
                           , [](int * x)
                           {
                               std::cout << "Destroying " << x << std::endl;
                               delete x;
                           });
    return [y = make_movable(std::move(x))]() mutable {
        std::cout << "value: " << *y() << std::endl;
        return;
    };
}

int main()
{
    {
        auto x = fn1();
        x();
        std::cout << "object still not deleted\n";
        x();
    }
    std::cout << "object was deleted\n";
}

move_with_copy_ctorवर्ग और यह सहायक समारोह make_movable()किसी भी चल नहीं बल्कि copyable वस्तु के साथ काम करेंगे। लिपटी हुई वस्तु तक पहुंच प्राप्त करने के लिए, का उपयोग करें operator()()

अपेक्षित उत्पादन:

मूल्य: 1
ऑब्जेक्ट अभी भी नहीं हटाया गया
मूल्य: 1
000000DFDD172280 को नष्ट करना
ऑब्जेक्ट हटा दिया गया था

खैर, सूचक पता भिन्न हो सकता है। ;)

Demo


1

यह gcc4.8 पर काम करता है

#include <memory>
#include <iostream>

struct Foo {};

void bar(std::unique_ptr<Foo> p) {
    std::cout << "bar\n";
}

int main() {
    std::unique_ptr<Foo> p(new Foo);
    auto f = [ptr = std::move(p)]() mutable {
        bar(std::move(ptr));
    };
    f();
    return 0;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.