2010-08-31 17 views
9

this question देखने के बाद, तो मेरा पहला विचार था कि यह सामान्य तुल्यता और संबंधपरक ऑपरेटर परिभाषित करने के लिए तुच्छ हो जाएगा:क्या यह एक सामान्य ऑपरेटर == और ऑपरेटर <को लागू करने का एक सुरक्षित तरीका है?

#include <cstring> 

template<class T> 
bool operator==(const T& a, const T& b) { 

    return std::memcmp(&a, &b, sizeof(T)) == 0; 

} 

template<class T> 
bool operator<(const T& a, const T& b) { 

    return std::memcmp(&a, &b, sizeof(T)) < 0; 

} 

using namespace std::rel_ops तो और भी अधिक उपयोगी, बन जाएगा, क्योंकि यह डिफ़ॉल्ट कार्यान्वयन से पूरी तरह से सामान्य किया जाएगा ऑपरेटरों के == और <। जाहिर है यह सदस्यवार तुलना नहीं करता है, बल्कि इसके बजाय थोड़ा सा, जैसा कि प्रकार में केवल पीओडी सदस्य हैं। उदाहरण के लिए, सदस्यवार प्रतिलिपि करने के लिए, उदाहरण के लिए, सी ++ कॉपी कन्स्ट्रक्टर कैसे उत्पन्न करता है, यह पूरी तरह से संगत नहीं है।

लेकिन मुझे आश्चर्य है कि उपरोक्त कार्यान्वयन वास्तव में सुरक्षित है या नहीं। संरचनाओं में स्वाभाविक रूप से एक ही प्रकार के समान पैकिंग होगी, लेकिन पैडिंग की सामग्री समान होने की गारंटी है (उदाहरण के लिए, शून्य से भरा)? क्या कोई कारण हैं या ऐसी परिस्थितियां जिनमें यह काम नहीं करेगा?

+2

आप ऐसा क्यों करना चाहते हैं? इसके बिना, यदि आपके पास ऑपरेटर की तुलना में समानता या कम नहीं है तो आपको एक सुविधाजनक सुविधाजनक संकलन त्रुटि मिल जाएगी। इसके साथ, संकलन त्रुटि चली गई है, और आप चुपचाप गलत ऑपरेटरों की संभावना है। आप ध्यान से इस तरह की बग बना रहे हैं कि उन्हें आसानी से नहीं देखा जाएगा। –

+0

http://rxwen.blogspot.com/2009/12/use-memcmp-to-compare-objects.html – DumbCoder

+0

@ डेविड: मैं निश्चित रूप से इसे वास्तविक कोड में उपयोग नहीं करता, लेकिन यह अटकलों को चोट नहीं पहुंचा सकता । –

उत्तर

2

यह बेहद खतरनाक है क्योंकि संकलक न केवल पुराने पुराने structs के लिए इन परिभाषाओं का उपयोग करेगा, बल्कि किसी भी कक्षा के लिए भी जटिल होगा, जिसके लिए आप == और < को ठीक से परिभाषित करना भूल गए हैं।

एक दिन, यह आपको काट देगा।

+0

आप डिफॉल्ट कॉपी कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर के बारे में बिल्कुल वही बात कह सकते हैं। एक डिजाइन दृष्टिकोण से यह कितना खतरनाक है वास्तव में मेरा सवाल नहीं है। एक अनिर्धारित/अनिर्दिष्ट/कार्यान्वयन-परिभाषित व्यवहार दृष्टिकोण से यह कितना खतरनाक है। –

0

बहुत समानता की आपकी परिभाषा पर निर्भर कर सकते हैं।

उदा। यदि आपके द्वारा कक्षाओं में तुलना करने वाले सदस्यों में से कोई भी फ़्लोटिंग पॉइंट नंबर हैं।

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

आमतौर पर ऐसी संख्याओं को उचित सहनशीलता के साथ संख्यात्मक रूप से तुलना की जानी चाहिए।

3

यहां तक ​​कि पीओडी के लिए, == ऑपरेटर गलत हो सकता है। यह संरचनाओं के संरेखण के कारण निम्न है जो मेरे कंपाइलर पर 8 बाइट्स लेता है।

class Foo { 
    char foo; /// three bytes between foo and bar 
    int bar; 
}; 
12

नहीं - सिर्फ उदाहरण के लिए, यदि आप टी == है (नाव | डबल | लंबे डबल), अपने operator== सही काम नहीं करता। दो NaN को बराबर की तुलना कभी नहीं की जानी चाहिए, भले ही उनके पास समान बिट पैटर्न हो (वास्तव में, NaN का पता लगाने का एक आम तरीका स्वयं की संख्या की तुलना करना है - यदि यह स्वयं के बराबर नहीं है, तो यह एक NaN है)। इसी तरह, 0 पर सेट किए गए उनके एक्सपोनेंट्स में सभी बिट्स के साथ दो फ़्लोटिंग पॉइंट नंबर मान 0.0 (बिल्कुल) हैं, इस पर ध्यान दिए बिना कि बिट्स को महत्व में सेट/स्पष्ट किया जा सकता है।

आपके operator< में सही तरीके से काम करने का भी कम मौका है। उदाहरण के लिए, कि कुछ इस तरह दिखता std::string का एक विशिष्ट कार्यान्वयन पर विचार करें: सदस्यों की इस आदेश के साथ

template <class charT> 
class string { 
    charT *data; 
    size_t length; 
    size_t buffer_size; 
public: 
    // ... 
}; 

, अपने operator< इसके बफ़र्स जहां तार होने के पते के आधार पर तुलना संगृहीत करना है कि उनके डेटा। यदि, उदाहरण के लिए, यह पहले length सदस्य के साथ लिखा गया था, तो आपकी तुलना तारों की लंबाई प्राथमिक कुंजी के रूप में उपयोग करेगी।किसी भी मामले में, यह वास्तविक स्ट्रिंग सामग्री के आधार पर तुलना नहीं करेगा, क्योंकि यह केवल data पॉइंटर के मान को देखेगा, जो कुछ भी इस बिंदु पर नहीं है, जो आप वास्तव में चाहते हैं/चाहते हैं।

संपादित करें: जहां तक ​​पैडिंग चलती है, वहां कोई आवश्यकता नहीं है कि पैडिंग की सामग्री बराबर हो। यह पैडिंग के लिए सैद्धांतिक रूप से संभव है कि किसी प्रकार का जाल प्रतिनिधित्व हो जो सिग्नल का कारण बनता है, अपवाद फेंकता है, या उस क्रम पर कुछ होता है, अगर आप इसे बिल्कुल भी देखने की कोशिश करते हैं। ऐसे जाल के प्रतिनिधित्व से बचने के लिए, आपको इसे unsigned char एस के बफर के रूप में देखने के लिए कलाकार की तरह कुछ उपयोग करने की आवश्यकता है। memcmp कि कर सकते हैं, लेकिन फिर यह नहीं हो सकता है ...

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

इनमें से कोई भी संभावित या आम नहीं है, लेकिन ऑफहैंड मैं मानक में कुछ भी नहीं सोच सकता जो उन्हें प्रतिबंधित करता है।

+0

मुझे पूरी तरह से पता है कि यह ज्यादातर स्थितियों के लिए * सही * काम नहीं करता है। मैं जो पूछ रहा हूं वह यह है कि क्या यह अनिश्चित, अनिर्दिष्ट, या कार्यान्वयन-परिभाषित व्यवहार को आविष्कार करता है कि वह संरचनाओं की थोड़ी सी तुलना (संभवतः गलत) धारणा के तहत पीओडी है। –

+0

आप कितने निश्चित हैं कि एक प्रकार के व्यक्तिगत उदाहरणों में अद्वितीय संरेखण आवश्यकताएं हो सकती हैं? कम से कम, यह वस्तु के आकार को प्रभावित करेगा, जिसकी अनुमति नहीं है। मैं देख सकता हूं कि यह कहां संभव हो सकता है, यह संरेखण नियमों की मेरी समझ के साथ ज़िंदा नहीं लगता है। –

+0

@ डेनिस: ठीक है, मुझे यकीन है कि मानक में कुछ भी नहीं है, विशेष रूप से इसे अनुमति देने के लिए, लेकिन ऑफहैंड मैं कुछ भी नहीं सोच सकता जो इसे प्रतिबंधित करेगा। ऐसा लगता है कि यह एकमात्र ऐसा समय उपयोगी हो सकता है जब इसे बेस क्लास के रूप में उपयोग किया जाता था, जो आकार (बेस_सोबोबजेक्ट) के बारे में नियमों को कम करता है। संरेखण को बदलना आवश्यक रूप से आकार को बदलता नहीं है - यह केवल तभी बदलता है जहां आप पैडिंग डालते हैं (सदस्यों के बीच संरचना बनाम के अंत में) - हालांकि यह ऐसा करने के लिए अधिकांश प्रेरणा को हटा देता है। –

0

कोई भी पॉइंटर वाला कोई भी स्ट्रक्चर या क्लास तुरंत किसी भी प्रकार की सार्थक तुलना में विफल हो जाएगा। वे ऑपरेटर केवल सादा पुराने डेटा, या पीओडी के किसी भी वर्ग के लिए काम करेंगे। एक अन्य उत्तरदाता ने फ्लोटिंग पॉइंट्स को एक मामले के रूप में सही ढंग से इंगित किया जब भी यह सच नहीं होगा, और पैडिंग बाइट्स।

संक्षिप्त उत्तर: यदि यह एक स्मार्ट विचार था, तो भाषा में यह डिफ़ॉल्ट प्रतिलिपि बनाने वाले/असाइनमेंट ऑपरेटर की तरह होगा।

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