2016-02-16 12 views
5

मैं एक बड़े सी ++ प्रोग्राम का विश्लेषण करने की कोशिश कर रहा हूं। कार्यक्रम एसटीएल कंटेनर डेटा स्ट्रक्चर जैसे सेट, मैप, अनॉर्डर्ड सेट, अनॉर्डर्ड मैप, वेक्टर इत्यादि का भारी उपयोग करता है। कभी-कभी वे घोंसले होते हैं, उदा। सेट का नक्शासी ++: किसी प्रोग्राम में सबसे बड़ा कंटेनर खोजें

मैं प्रोग्राम के एक विशेष भाग में, जानना चाहता हूं कि कंटेनरों में सबसे बड़ी संख्या में तत्व हैं (यानी आकार() का सबसे बड़ा मूल्य)। मैं कार्यक्रम में मामूली संपादन कर सकता हूं।

यदि सभी कंटेनरों पर पुनरावृत्ति करने का कोई तरीका था, या यदि कंटेनरों के एपीआई (आकार संशोधित) को अवरुद्ध करने का कोई तरीका था, तो यह सहायक हो सकता है। लेकिन ये संभव नहीं हैं।

आप इस पर कैसे पहुंचेंगे?

अतिरिक्त: लिनक्स में प्लेटफ़ॉर्म, कंपाइलर या तो g ++ या clang ++ है।

+5

मैं ऐसे valgrind या शुद्ध रूप में एक स्मृति निगरानी उपकरण का प्रयोग करेंगे। – SergeyA

+1

आप किस मंच पर हैं? मैं उस उपकरण का उपयोग करके इस पर पहुंचूंगा जो ग्लोबल मेमोरी आवंटक को हुक करता है। विजुअल स्टूडियो 2015 में आवंटन का विश्लेषण करने के लिए उपकरणों में शक्तिशाली बनाया गया है, उपकरण अन्य प्लेटफॉर्म के लिए भी मौजूद हैं। – mattnewport

+0

@ सर्गेय: क्या आप कृपया उल्लेख कर सकते हैं कि यहां वाल्ग्रिंड का उपयोग कैसे किया जा सकता है? – Arun

उत्तर

2

यह विधि तब उपयोगी होती है जब आपकी परियोजना वास्तव में बड़ी होती है और विभिन्न कंटेनरों के बहुत अधिक उदाहरण होते हैं। विधि का लाभ यह है कि आपको बड़ी मात्रा में कोड को संशोधित करने की आवश्यकता नहीं है। यह आपको कंटेनर को खोजने के लिए संकीर्ण प्रकार की अनुमति देता है। यह विधि प्रत्येक contaier और प्रति प्रकार की स्थिति को व्यवस्थित करने में मदद करती है।

template< class T > struct allocator को फिर से परिभाषित करना संभव है। एसडी हेडर में मूल आवंटक का नाम बदलना या इसे संशोधित करना संभव है। आवंटन और हटाने के लिए आंकड़े करना संभव बनाएं। आप प्रति प्रकार के तत्वों की गणना और आकार जानेंगे। लेकिन आप नहीं जानते कि कंटेनर का कौन सा उदाहरण तत्व है।

टेम्पलेट template< class T > struct allocator लाइब्रेरी हेडर फ़ाइलों पर रखा गया। यह हमेशा मौजूद है और आपके विकास पर्यावरण पुस्तकालय को पुनर्निर्माण करने की आवश्यकता नहीं है, क्योंकि जहां तक ​​आप जानते हैं कि स्थैतिक पुस्तकालय में संकलन करना संभव नहीं है (विशेषज्ञता को छोड़ दें)। टेम्पलेट्स हमेशा आपके स्रोतों के साथ संकलित। लेकिन precompiled हेडर के साथ समस्या हो सकती है। प्रोजेक्ट के लिए इसे पुनर्जीवित करना या इसका उपयोग नहीं करना संभव है, लेकिन पुस्तकालय के लिए इसे जांचना आवश्यक है। संभव है कि यह विधि की बाधा है, लेकिन मौजूदा समस्या को सत्यापित करना आसान है या नहीं।

एक अनुभवजन्य विधि है जो सटीकता की गारंटी नहीं देती है। जब आपका एप्लिकेशन बंद हो जाता है, तो उसके तत्वों को हटाए जाने के बाद कंटेनर को हटा दिया जाता है। तो आप माता-पिता के प्रति कंटेनर के आंकड़े लिख सकते हैं कि किस प्रकार के कंटेनर पर आंतरिक तत्व कितने थे।

उदाहरण के लिए दें हमने:

vector<A>({1,2,3}) and map<string,B>({1,2}) and map<string,B>({1,2}) 

यह इस तरह आवंटन रद्द घटना सूची उत्पन्न होगी:

B, B, map<string,B>, 
A, A, map<string,A>, 
A, A, A, vector<A>, 

तो आप को पता कर सकते हैं कि 3 तत्वों Avector<A> पर, 2 तत्वों Amap<string,A> पर, और 2 तत्व Amap<string,A>

+0

स्टडी हेडर बदलना कोशेर नहीं है। – BitWhistler

+1

कोशेर। जब यह पर्याप्त मुश्किल समस्या को हल करने में मदद करता है। और यह केवल विकास पर्यावरण में है। यह उत्पादन में कोशेर भी है जब यह समस्या हल करने में मदद करता है और रोलबैक जितनी जल्दी हो सके किया जाएगा। यदि एसडीडी बदलना std lib और आईडीई विकसित करने से कोशेर नहीं है और ओएस भी कोशेर नहीं है। – oklas

2

यदि आप मामूली संपादन कर सकते हैं, क्या आप प्रत्येक कंटेनर को उनकी एक बड़ी सूची में जोड़ सकते हैं?
इस तरह:

std::set<......> my_set; // existing code 
all_containers.add(&my_set); // minor edit IMHO 

तो फिर तुम all_containers.analyse() कॉल कर सकते हैं कि चाहते हैं उनमें से प्रत्येक पर size() फोन और परिणाम मुद्रित।

struct ContainerStatsI { 
    virtual int getSize() = 0; 
}; 
template<class T> struct ContainerStats : ContainerStatsI { 
    T* p_; 
    ContainerStats(T* p) : p_(p) {} 
    int getSize() { return p->size(); } 
}; 
struct ContainerStatsList { 
    std::list<ContainerStatsI*> list_; // or some other container.... 
    template<class T> void add(T* p) { 
    list_.push_back(new ContainerStats<T>(p)); 
    } 
    // you should probably add a remove(T* p) as well 
    void analyse() { 
    for(ContainerStatsI* p : list_) { 
     p->getSize(); // do something with what's returned here 
    } 
    } 
}; 
+0

मैक्रोज़ का उपयोग करना संभव है, जो all_containers फ़ाइल और लाइन को पास करता है जहां कंटेनर वास्तव में बनाया गया है। – oklas

+0

आप इसे फ़ाइल के लिए मैक्रो के साथ कर सकते हैं: लाइन या आप ऐड विधि में कुछ स्ट्रिंग नाम, या आईडी के किसी अन्य रूप को जोड़ सकते हैं। – BitWhistler

+0

विचार के लिए धन्यवाद। 'कंटेनरस्टैट *' कक्षाएं जोड़ना बहुत संभव है लेकिन प्रत्येक कंटेनर के लिए 'add() 'में कॉल जोड़ना भयानक है। हम नेस्टेड कंटेनर को कैसे संबोधित करते हैं, उदा। एक int से एक सेट के लिए एक नक्शा? – Arun

1

एसटीडी हेडर फाइल में कंटेनरों की विनाशकर्ता करने के लिए आंकड़े कोड जोड़ें:

आप ऐसा ही कुछ कर सकते हैं। बड़ी परियोजना के बड़े पैमाने पर कोड को संशोधित करने की आवश्यकता नहीं है। लेकिन यह केवल कंटेनर प्रकार भी दिखाता है (यहां मेरा दूसरा जवाब देखें)। विधि को C++ 0x या C++ 11 या किसी और की आवश्यकता नहीं है।

पहले और अनिवार्य कदम त्वरित दृश्य क्या वास्तव में बदल दिया गया है के लिए और संशोधित और मूल संस्करण के बीच त्वरित स्विच के लिए स्रोत नियंत्रण, उदाहरण के लिए Git के तहत अपने एसटीडी पुस्तकालय को जोड़ने के लिए, है।

प्लेस एसटीडी पुस्तकालय सूत्रों फ़ोल्डर में Stat वर्ग की इस घोषणा:

class Stat { 
    std::map<std::string,int> total; 
    std::map<std::string,int> maximum; 
public: 
    template<class T> 
    int log(std::string cont, size_t size) { 
     std::string key = cont + ": " + typeid(T).name(); 
     if(maximum[key] < size) maximum[key] = size; 
     total[key] += size; 
    } 
    void show_result() { 
     std::cout << "container type total maximum" << std::endl; 
     std::map<std::string,int>::const_iterator it; 
     for(it = total.begin(); it != total.end(); ++it) { 
      std::cout << it->first << " " << it->second 
       << " " << maximum[it->first] << std::endl; 
     } 
    } 
    static Stat& instance(); 
    ~Stat(){ show_result(); } 
}; 

का दृष्टांत Stat वर्ग की सिंगलटन के कहने अपनी परियोजना cpp फ़ाइल पर:

Stat& Stat::instance() { 
    static Stat stat; 
    return stat; 
} 

संपादित एसटीडी पुस्तकालय कंटेनर टेम्पलेट्स। विनाशकों पर सांख्यिकीय लॉगिंग जोड़ें।

// modify this standart template library sources: 

template< T, Allocator = std::allocator<T> > vector { 
    ... 
    virtual ~vector() { 
     Stat::instance().log<value_type>("std::vector", this->size()); 
    } 
}; 

template< Key, T, Compare = std::less<Key>, 
    Allocator = std::allocator<std::pair<const Key, T> > map { 
    ... 
    virtual ~map(){ 
     Stat::instance().log<value_type>("std::map", this->size()); 
    } 
}; 

अब उदाहरण के लिए एक कार्यक्रम पर विचार करें:

int main() { 
    { 
     // reject to use C++0x, project does not need such dependency 
     std_vector<int> v1; for(int i=0;i<10;++i) v1.push_back(i); 
     std_vector<int> v2; for(int i=0;i<10;++i) v2.push_back(i); 
     std_map<int,std::string> m1; for(int i=0;i<10;++i) m1[i]=""; 
     std_map<int,std::string> m2; for(int i=0;i<20;++i) m2[i]=""; 
    } 
    Stat::instance().show_result(); 
    return 0; 
} 

जीसीसी के लिए परिणाम है:

container type total maximum 
std::map: St4pairIiSsE 30 20 
std::vector: i 20 10 

आप अधिक विस्तृत प्रकार desription से जानकारी के विषय में लगता है की जरूरत है अपने विकास पर्यावरण। इस तरह के रूपांतरण यहाँ जीसीसी के लिए वर्णित: https://lists.gnu.org/archive/html/help-gplusplus/2009-02/msg00006.html

आउटपुट इस तरह हो सकता है:

container type total maximum 
std::map: std::pair<int, std::string> 30 20 
std::vector: int 20 10 
+0

उपनाम में बदलना आसान हो सकता है लेकिन संभवतः सबसे गंदे दृष्टिकोण संभव है। – BitWhistler

+1

रेली डर्टी बिना तर्क के बोलते हैं। – oklas

+0

अपने स्थिर डेटा पर ध्यान दें। स्टेट इंस्टेंस नष्ट होने के बाद इसे नष्ट कर दिया जा सकता है। ऐसा डेटा कभी-कभी स्टेट के लिए "दिखाई नहीं दे सकता" जैसा हो सकता है। – oklas

संबंधित मुद्दे