2012-06-18 10 views
12

कल्पना कीजिए कि आप एक फ़ाइल आहजी ++, कई टेम्प्लेट विशेषज्ञता के लिए लिंकर चेतावनी/त्रुटि की आवश्यकता होती है

#include <iostream> 

template<typename T> struct A{ 
    int magic; 
    A():magic(1234){} 
    void f(){std::cout<<"default f"<<magic<<std::endl;} 
}; 


void f(A<int>* a); 

तो समारोह च "a.cpp"

#include "a.h" 
void f(A<int>* a){ 
    a->f(); 
} 

और अंत में परिभाषित किया गया है है, " main.cpp "टेम्पलेट माहिर हैं, और फिर च

#include "a.h" 
template<> struct A<int>{ 
}; 

int main(){ 
    A<int> a; 
    f(&a); 

} 

का उपयोग करता है जाहिर संकलक Ao के लिए गैर विशेष संस्करण का उपयोग करता है, और main.o के लिए विशेष संस्करण, यानी ए के दो अलग-अलग कार्यान्वयन होते हैं निष्पादन पर, एफ केवल कचरा/सेगफॉल्ट प्रिंट कर सकता है, क्योंकि ऑब्जेक्ट पास की गई उम्मीद से एक अलग संरचना होती है।

क्या लिंकर को चेतावनी देने का कोई तरीका है कि ए के दो संस्करण हैं?

+0

यह हल करने में एक कठिन समस्या है, यही कारण है कि इसके लिए कोई अनिवार्य निदान नहीं है। – Flexo

+0

एचटीएच: प्रश्न से सभी टेम्पलेट हटा दें - और आपके पास एक ही परिणाम होगा। स्ट्रक्चर ए के एएच में केवल आगे की घोषणा छोड़ दें; और इसे पूर्ण संस्करण को a.cpp पर ले जाएं। main.cpp - केवल खाका हटा ... – PiotrNycz

उत्तर

3

गोल्ड इस बारे में चेतावनी नहीं देता है कि गोल्ड केवल प्रतीक विसंगतियों (एक ही प्रतीक को असंगत तरीकों से एकाधिक ऑब्जेक्ट फ़ाइलों में परिभाषित किया जा रहा है) का पता लगाता है, और उदाहरण में ऐसा कोई मेल नहीं है।

वेलग्रिंड तहत उदाहरण चल रहा है, हालांकि यह त्रुटि उत्पन्न करता है:

valgrind --track-origins=yes ./a.out 

==11004== Memcheck, a memory error detector 
==11004== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==11004== Using Valgrind-3.8.0.SVN and LibVEX; rerun with -h for copyright info 
==11004== Command: ./a.out 
==11004== 
==11004== Conditional jump or move depends on uninitialised value(s) 
==11004== at 0x40B6D24: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40B703C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40C26DE: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40094F: A<int>::f() (a.h:6) 
==11004== by 0x4008CB: f(A<int>*) (a.cpp:3) 
==11004== by 0x400977: main (main.cpp:7) 
==11004== Uninitialised value was created by a stack allocation 
==11004== at 0x400964: main (main.cpp:5) 

आप Address Sanitizer से भी बेहतर रिपोर्ट मिलना चाहिए:

अद्यतन:

मुद्दा यह है कि मैं चाहते हैं समय को जोड़ने पर त्रुटि का पता लगाने के लिए, निष्पादन के दौरान नहीं।

मैं आपकी बात समझता हूं, लेकिन वर्तमान में यह संकलक (अन्य अनुवाद इकाइयों के बारे में जानकारी नहीं है) या लिंकर (इसमें शामिल प्रकारों के बारे में जानकारी नहीं है) के लिए यह संभव नहीं है ।

अब, डीबग बिल्ड के लिए, लिंकर सिद्धांत में ऐसा कर सकता है, अगर प्रत्येक फ़ंक्शन के लिए यह पैरामीटर प्रकारों के लिए डीबग जानकारी की तुलना भी करता है। मैं bugzilla में सोने के लिए एक फीचर अनुरोध दर्ज करने का सुझाव देता हूं।

+1

धन्यवाद। मुझे वास्तव में पता चला कि यह स्थिति वालग्रींड का उपयोग करके मेरे कोड में हो रही थी, और फिर मैंने यह खिलौना उदाहरण प्राप्त किया। मुद्दा यह है कि मैं निष्पादन के दौरान नहीं, समय जोड़ने पर त्रुटि का पता लगाना चाहता हूं। –

1

सोने लिंकर --detect-ओडीआर-उल्लंघन

यह प्रत्येक टेम्पलेट परिभाषा के लिए फ़ाइल और लाइन संख्या की तुलना और चेतावनी अगर वे सभी एक ही नहीं कर रहे हैं से काम करता है के साथ एक चेतावनी दे सकता है।

+0

धन्यवाद, लेकिन ld -संस्करण जीएनयू सोना (उबंटू 2.21.53.20110810 के लिए जीएनयू binutils) 1.11 और जी ++ -ओ परीक्षण main.cpp a.cpp -Wl, --detect-odr-violations -Wall कोई चेतावनी नहीं देता –

+0

यह डीबग जानकारी का उपयोग करता है, इसलिए –

+0

जोड़ने का प्रयास करें। अभी भी जी ++ जी -c main.cpp जी ++ जी -c a.cpp जी ++ जी -ओ परीक्षण main.o Ao -Wl, - -Wall का पता लगाने-ओडीआर-उल्लंघन नहीं चेतावनी देता है के लिए एक ही g ++ -g -o test main.cpp a.cpp -Wl, - पता-odr-violations -Wall –

1

मुझे लगता है कि उत्तर "नहीं" है और यह इस तरह से रहने जा रहा है।

प्रकार केवल लिंकर नाम देखता है जब वे फ़ंक्शन पैरामीटर या टेम्पलेट तर्क (कुछ अन्य oddballs? शायद) में दिखाई देते हैं। आपका उदाहरण वास्तव में आसान मामलों में से एक है, और यह पता लगाने के लिए कि लिंकर को एबीआई के साथ काम करना होगा (प्रभाव में) एक विशेषज्ञता द्वारा आपूर्ति किए गए टेम्पलेट तर्कों को चिह्नित करता है। लेकिन वे ऐसा नहीं कर सकते हैं: आपको एक स्पष्टीकरण के लिए संकेत देने के बिना एक टेम्पलेट स्ट्रक्चर में पॉइंटर पास करने में सक्षम होना चाहिए।

फिर भी, आप छोटे एबीआई परिवर्तनों की तुलना में अधिक कट्टरपंथी नहीं हो सकते हैं, इसका अर्थ यह है कि कम से कम यह विचार करना है कि आपको प्रत्येक लाइब्रेरी और निष्पादन योग्य को पुनः संयोजित करने और/या फिर से जोड़ने की आवश्यकता है या नहीं।यदि आपके structs सदस्य struct trojan { A<int> greeks; } थे तो आपके पास समान प्रकार के नाम होंगे, और यदि वे फ़ंक्शन पैरामीटर या टेम्पलेट तर्क के रूप में कभी नहीं दिखाई देते हैं तो लिंकर उन्हें कभी भी नहीं देख पाएंगे, भले ही वे अलग थे।

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

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