मैं एक जटिल टेम्पलेट पैरामीटर प्रकार के साथ एक एसटीएल सेट लागू कर रहा हूं। सेट में सम्मिलित करते समय, मैं चाहता हूं कि सेट मेरे प्रकार के लिए परिभाषित कम-से-कम ऑपरेटर का उपयोग करे। मैं भी अपने प्रकार के ऑब्जेक्ट इंस्टेंटेशन की मात्रा को कम करना चाहता हूं। ऐसा लगता है कि मेरे पास दोनों नहीं हो सकते।

मेरे पास नीचे दो न्यूनतम उदाहरण हैं, प्रत्येक एक ही सी ++ कक्षा का उपयोग करता है।

#include <iostream>
#include <set>

using namespace std;

class Foo {
    public:
        Foo(int z);
        Foo(const Foo &z);
        bool operator<(const Foo &rhs) const;
        int a;
};

Foo::Foo(int z)
{
    cout << "cons" << endl;
    a = z;
}

Foo::Foo(const Foo &z)
{
    cout << "copy cons" << endl;
    a = z.a;
}

bool
Foo::operator<(const Foo &rhs) const
{
    cout << "less than" << endl;
    return a < rhs.a;
}

यहाँ मेरा पहला मुख्य है ():

int
main(void)
{
    set<Foo> s;

    s.insert(*new Foo(1));
    s.insert(*new Foo(2));
    s.insert(*new Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

यह बहुत अच्छा है क्योंकि यह मेरी कक्षा के लिए मेरे द्वारा परिभाषित कम-से-कम का उपयोग करता है, और इस प्रकार सेट का आकार सही ढंग से दो है। लेकिन यह बुरा है क्योंकि सेट में प्रत्येक प्रविष्टि के लिए दो वस्तुओं (कन्स्ट्रक्टर, कॉपी कंस्ट्रक्टर) की तात्कालिकता की आवश्यकता होती है।

$ ./a.out
cons
copy cons
cons
less than
less than
less than
copy cons
cons
less than
less than
less than
size: 2

यहाँ मेरा दूसरा मुख्य है ():

int
main(void)
{
    set<Foo *> s;

    s.insert(new Foo(1));
    s.insert(new Foo(2));
    s.insert(new Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

यह बहुत अच्छा है क्योंकि एक सम्मिलन के लिए केवल एक ऑब्जेक्ट इंस्टेंटेशन की आवश्यकता होती है। लेकिन यह बुरा है क्योंकि यह वास्तव में पॉइंटर्स का एक सेट है, और इस प्रकार सेट सदस्यों की विशिष्टता मेरे प्रकार के संबंध में चली गई है।

$ ./a.out
cons
cons
cons
size: 3

मुझे उम्मीद है कि कुछ जानकारी है जो मुझे याद आ रही है। क्या मेरे लिए न्यूनतम वस्तु तात्कालिकता और उपयुक्त छँटाई दोनों संभव है?

-1
Syrinx 27 अगस्त 2011, 10:05
आपको क्यों लगता है कि एक कॉपी कंस्ट्रक्टर महंगा है और ऑपरेटर new का उपयोग करना नहीं है?
 – 
Bo Persson
27 अगस्त 2011, 14:22
महंगा? मुझे आपका प्रश्न समझ नहीं आ रहा है (हो सकता है कि आप मेरा प्रश्न न समझें)। मेरी समस्या दोनों एक कॉपी कंस्ट्रक्टर और कंस्ट्रक्टर (दो ऑब्जेक्ट्स) के साथ है जिसे हर इंसर्शन के लिए बुलाया जा रहा है। मुझे परवाह नहीं है कि कौन सा अधिक महंगा है। दोनों का योग वह है जिससे मैं बचने की कोशिश कर रहा हूं।
 – 
Syrinx
28 अगस्त 2011, 04:59
मैं new का उपयोग करने से बचने की कोशिश करूंगा, क्योंकि मैं जानता हूं कि वह महंगा है। एक अतिरिक्त कंस्ट्रक्टर की तुलना में शायद अधिक महंगा है।
 – 
Bo Persson
28 अगस्त 2011, 11:38

3 जवाब

सबसे बढ़िया उत्तर

आपको इसकी एक प्रति मिल रही है: *new Foo(1)

यह संरचना बनाएं:

template<typename T>
struct PtrLess
{
    bool operator()(const T *a, const T *b) const
    {
        return *a < *b;
    }
};

मानचित्र को set<Foo*, PtrLess<Foo>> s; जैसा बनाएं और फिर Foo's जैसे s.insert(new Foo(1)); जोड़ें ध्यान दें *

अन्यथा, जब नक्शा फू आइटम के लिए एक कंटेनर बनाता है, क्योंकि इसे फू कंटेनर परिभाषा के भीतर आवंटित किया जाता है, तो मानचित्र को आपूर्ति किए गए मान को अपने आंतरिक फू ऑब्जेक्ट में कॉपी करना होगा।

1
Mranz 27 अगस्त 2011, 10:17
मृंज, मुझे लगता है कि आपने पूरा प्रश्न नहीं पढ़ा। आपका सुझाव काम नहीं करेगा क्योंकि आप छँटाई खो देते हैं।
 – 
Syrinx
27 अगस्त 2011, 10:14
क्षमा करें, मैं इसका एक भाग भूल गया। मैंने अपना जवाब संशोधित किया।
 – 
Mranz
27 अगस्त 2011, 10:17
यह Foo* डालते समय तुलना की समस्या को हल करता है, लेकिन स्मृति रिसाव की समस्या के बारे में क्या?
 – 
Praetorian
27 अगस्त 2011, 10:31
जैसा कि म्रांज ने नीचे उल्लेख किया है, मैं सेट के दायरे से बाहर होने से पहले आवश्यक वस्तुओं को हटा दूंगा। कोई स्मृति रिसाव नहीं।
 – 
Syrinx
27 अगस्त 2011, 10:33
प्रस्तावित समाधान के साथ कोई अंतर्निहित स्मृति रिसाव नहीं है, यह मानते हुए कि सेट के दायरे से पहले कहीं नीचे की रेखा है, आप सेट पर पुनरावृति करते हैं और हटाते हैं।
 – 
Mranz
27 अगस्त 2011, 10:33

मानक कंटेनर जोड़े गए आइटम की एक प्रति संग्रहीत करते हैं। यदि आप चाहते हैं कि आपका set पॉइंटर्स के बजाय ऑब्जेक्ट्स को स्टोर करे, तो आपको बस निम्न कार्य करना चाहिए, अन्यथा आप एक मेमोरी लीक बना रहे हैं, क्योंकि new के माध्यम से आवंटित ऑब्जेक्ट कभी भी संबंधित के माध्यम से मुक्त नहीं होते हैं। delete.

int main()
{
    set<Foo> s;

    s.insert(Foo(1));
    s.insert(Foo(2));
    s.insert(Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

यदि आप तत्काल अस्थायी वस्तुओं की संख्या को कम करना चाहते हैं, तो केवल एक अस्थायी का उपयोग करें:

int main()
{
    set<Foo> s;

    Foo temp(1);
    s.insert(temp);
    temp.a = 2;
    s.insert(temp);
    temp.a = 1;
    s.insert(temp);

    cout << "size: " << s.size() << endl;

    return 0;
}

इस स्निपेट का आउटपुट (ideone के माध्यम से) है:

cons
copy cons 
less than
less than
less than
copy cons
less than
less than
less than
size: 2

आम तौर पर, मैं वास्तविक वस्तुओं को set<Foo*> में वस्तुओं के पॉइंटर्स के बजाय set<Foo> में स्टोर करना पसंद करूंगा, क्योंकि ऑब्जेक्ट स्वामित्व के साथ कोई समस्या नहीं हो सकती है (कौन/कब new और delete को कॉल करने की आवश्यकता है), आवंटित मेमोरी की कुल मात्रा कम है (N आइटम के लिए आपको N*(sizeof(Foo) + sizeof(Foo*)) बाइट्स के बजाय N*sizeof(Foo) की आवश्यकता है) और डेटा एक्सेस सकता है< /em> आमतौर पर तेज होने की उम्मीद की जाती है (क्योंकि कोई अतिरिक्त सूचक संकेत नहीं है)।

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

1
Darren Engwirda 27 अगस्त 2011, 10:38
यह केवल एक स्मृति रिसाव होगा यदि सेट के दायरे को छोड़ने के समय तक पॉइंटर्स को हटाया नहीं गया था। मुझे लगता है कि यह एक काल्पनिक उदाहरण है क्योंकि अधिकांश वास्तविक कार्यक्रमों में Foo वर्ग नहीं होता है।
 – 
Mranz
27 अगस्त 2011, 10:23
2
@Mranz: मैं पहले उदाहरण के बारे में बात कर रहा हूं जहां सेट std::set<Foo> है। इस मामले में अस्थायी वस्तुएं *new Foo(1) etc के माध्यम से बनाई जाती हैं, जो कि allocating/constructing ढेर पर नई वस्तुएं हैं लेकिन इन वस्तुओं के लिए पॉइंटर्स को कभी भी संग्रहीत नहीं करती हैं। फिर delete को destruct/free पर कॉल करने का कोई तरीका नहीं है। यह एक स्मृति रिसाव है ...
 – 
Darren Engwirda
27 अगस्त 2011, 10:30
आह हाँ, तुम बिल्कुल सही हो। मैं उस हिस्से के बारे में भूल गया :)
 – 
Mranz
27 अगस्त 2011, 10:32

यह @Mranz के उत्तर का विस्तार है। . कच्चे पॉइंटर्स से निपटने के बजाय, पॉइंटर्स को std::unique_ptr में रखें

#include <memory>

using namespace std;

template<typename T>
struct PtrLess
{
    bool operator()(const T& a, const T& b) const
    {
        return *a < *b;
    }
};


int
main(void)
{
    set<unique_ptr<Foo>, PtrLess<unique_ptr<Foo>>> s;

    s.insert(unique_ptr<Foo>(new Foo(1)));
    s.insert(unique_ptr<Foo>(new Foo(2)));
    s.insert(unique_ptr<Foo>(new Foo(1)));

    cout << "size: " << s.size() << endl;

    return 0;
}
0
Community 23 मई 2017, 15:19