चार्ट में एक कुंजी के रूप में * का उपयोग करना :: मानचित्र


81

मैं यह पता लगाने की कोशिश कर रहा हूं कि निम्न कोड क्यों काम नहीं कर रहा है, और मुझे लगता है कि यह चार प्रकार के कुंजी के रूप में * का उपयोग करने के साथ एक मुद्दा है, हालांकि मुझे यकीन नहीं है कि मैं इसे कैसे हल कर सकता हूं या यह क्यों हो रहा है। मेरे द्वारा उपयोग किए जाने वाले अन्य कार्यों (HL2 SDK में) का char*उपयोग std::stringकरने से सभी अनावश्यक जटिलताओं का कारण बनने जा रहा है।

std::map<char*, int> g_PlayerNames;

int PlayerManager::CreateFakePlayer()
{
    FakePlayer *player = new FakePlayer();
    int index = g_FakePlayers.AddToTail(player);

    bool foundName = false;

    // Iterate through Player Names and find an Unused one
    for(std::map<char*,int>::iterator it = g_PlayerNames.begin(); it != g_PlayerNames.end(); ++it)
    {
        if(it->second == NAME_AVAILABLE)
        {
            // We found an Available Name. Mark as Unavailable and move it to the end of the list
            foundName = true;
            g_FakePlayers.Element(index)->name = it->first;

            g_PlayerNames.insert(std::pair<char*, int>(it->first, NAME_UNAVAILABLE));
            g_PlayerNames.erase(it); // Remove name since we added it to the end of the list

            break;
        }
    }

    // If we can't find a usable name, just user 'player'
    if(!foundName)
    {
        g_FakePlayers.Element(index)->name = "player";
    }

    g_FakePlayers.Element(index)->connectTime = time(NULL);
    g_FakePlayers.Element(index)->score = 0;

    return index;
}

14
कभी-कभी सही काम करने से पहले दर्द होता है। std:stringएक बार उपयोग करने के लिए अपना कोड बदलें , और बाद में खुश रहें।
ब्योर्न पॉलेक्स

1
किस तरह की जटिलताओं? char * से std :: string में निहित रूपांतरण है।
१ .:

1
आपको char*मानचित्र कुंजी के रूप में उपयोग नहीं करना चाहिए । मेरा जवाब क्यों देखें ।
भारतीय स्टेट बैंक

यह उपयोग करने के कारण होने वाली एक अनावश्यक जटिलता प्रतीत होती है std::string
पेड्रो डी'क्वीनो

मुझे समझ में नहीं आता है, एक बाइनरी कुंजी का उपयोग करने के लिए, क्या मानचित्र को यह जानने की आवश्यकता नहीं होगी कि क्या एक कुंजी समान जानने के बजाय यह है कि एक कुंजी का मान दूसरे से कम है?
कोडमाइन

जवाबों:


140

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

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

struct cmp_str
{
   bool operator()(char const *a, char const *b) const
   {
      return std::strcmp(a, b) < 0;
   }
};

map<char *, int, cmp_str> BlahBlah;

2
वास्तव में वह सिर्फ &std::strcmpतीसरे टेम्पलेट पैरामीटर के रूप में पास कर सकते हैं
आर्मेन त्सिरुयान

23
नहीं, strcmpएक सकारात्मक, शून्य या नकारात्मक पूर्णांक देता है। नक्शे के फ़नकार को कम-से-कम और असत्य पर सही लौटने की आवश्यकता है।

4
@Armen: मुझे नहीं लगता कि यह काम करता है, क्योंकि 3rd टेम्पलेट पैरामीटर कुछ की तरह उम्मीद करता है f(a,b) = a<b, नहीं f(a,b) = (-1 if a<b, 1 if a>b, 0 else)
kennytm

28
ओह, क्षमा करें, मेरा बुरा, पोस्ट करने से पहले नहीं सोचा था। टिप्पणी को वहीं रहने दें और मेरे पूर्वजों के लिए शर्म की बात करें :)
Armen Tsirunyan

2
जैसा कि मैंने परीक्षण किया है, यह बूल ऑपरेटर () (चार कास्ट * ए, चार कॉन्स्टेंट * बी), बूल ऑपरेटर () (चार कॉन्स्ट * ए, चार कॉन्स्ट * बी) कॉन्स्ट {
ब्लाब्ला

45

आप उपयोग नहीं कर सकते char*जब तक आप पूरी तरह से 100% कर रहे हैं सुनिश्चित करें कि आप के साथ नक्शा देखने के लिए जा रहे हैं ठीक उसी संकेत दिए गए , नहीं तार।

उदाहरण:

char *s1; // pointing to a string "hello" stored memory location #12
char *s2; // pointing to a string "hello" stored memory location #20

यदि आप मानचित्र को अपने साथ एक्सेस करते हैं s1तो आपको इसके साथ पहुँचने की तुलना में एक अलग स्थान मिलेगा s2


5
जब तक आप अपने स्वयं के तुलनित्र को परिभाषित नहीं करते, जैसा कि स्वीकृत उत्तर में बताया गया है।
लुकास कालिंस्की

23

दो सी-स्टाइल स्ट्रिंग्स में समान सामग्री हो सकती है लेकिन अलग-अलग पते पर हो। और यह mapसंकेत की तुलना करता है, सामग्री की नहीं।

रूपांतरित करने की लागत std::map<std::string, int>उतनी नहीं हो सकती जितनी आप सोचते हैं।

लेकिन अगर आपको वास्तव const char*में मानचित्र कुंजियों के रूप में उपयोग करने की आवश्यकता है , तो कोशिश करें:

#include <functional>
#include <cstring>
struct StrCompare : public std::binary_function<const char*, const char*, bool> {
public:
    bool operator() (const char* str1, const char* str2) const
    { return std::strcmp(str1, str2) < 0; }
};

typedef std::map<const char*, int, StrCompare> NameMap;
NameMap g_PlayerNames;

जानकारी के लिए धन्यवाद। अपने अनुभव के आधार पर मैं अत्यधिक std :: string में बदलने की सलाह देता हूं।
user2867288

8

आप इसके साथ काम कर सकते हैं std::map<const char*, int>, लेकिन गैर- constपॉइंटर्स ( constकुंजी के लिए जोड़ा गया नोट) का उपयोग नहीं करना चाहिए , क्योंकि आपको उन तारों को बदलना नहीं चाहिए, जबकि नक्शा उन्हें कुंजी के रूप में संदर्भित करता है। (एक नक्शे के उन के माध्यम से अपने कुंजी की रक्षा करता है जबकि const, यह केवल constify हैं सूचक स्ट्रिंग नहीं है, यह करने के लिए इंगित करता है।)

लेकिन तुम बस का उपयोग क्यों नहीं करते std::map<std::string, int>? यह बिना सिरदर्द के बॉक्स से बाहर काम करता है।


8

आप char *एक स्ट्रिंग का उपयोग करके तुलना कर रहे हैं । वे एक जैसे नहीं हैं।

A char *, char का सूचक है। अंततः, यह एक पूर्णांक प्रकार है, जिसका मान एक के लिए एक वैध पते के रूप में व्याख्या किया गया है char

एक स्ट्रिंग एक स्ट्रिंग है।

कंटेनर सही ढंग से काम करता है, लेकिन जोड़े के लिए एक कंटेनर के रूप में जिसमें कुंजी एक है char *और मूल्य एक है int


1
पॉइंटर के लिए लंबे पूर्णांक होने की आवश्यकता नहीं है। प्लेटफ़ॉर्म हैं (ऐसा win64, अगर आपने कभी इसके बारे में सुना है :-)) जहां एक लंबा पूर्णांक एक सूचक से छोटा होता है, और मेरा मानना ​​है कि अधिक अस्पष्ट प्लेटफ़ॉर्म भी हैं जहां पॉइंटर्स और पूर्णांक अलग-अलग रजिस्टरों में लोड किए जाते हैं और अलग-अलग तरीके से व्यवहार किए जाते हैं दूसरा तरीका। C ++ के लिए केवल यह आवश्यक है कि पॉइंटर्स को कुछ अभिन्न प्रकार और बैक में परिवर्तित किया जाए; ध्यान दें कि इसका मतलब यह नहीं है कि आप किसी भी पर्याप्त छोटे पूर्णांक को सूचक के लिए डाल सकते हैं, केवल वे ही जो आपको सूचक को परिवर्तित करने से मिले हैं।
क्रिस्टोफर Creutzig

@ChristopherCreutzig, आपकी टिप्पणी के लिए धन्यवाद। मैंने उसी के अनुसार अपना उत्तर संपादित किया।
डैनियल डारनास

2

जैसा कि दूसरों का कहना है, आपको इस मामले में शायद एक चार * की जगह std :: string का उपयोग करना चाहिए, हालांकि एक पॉइंटर के साथ सिद्धांत में कुछ भी गलत नहीं है यदि यह वास्तव में आवश्यक है।

मुझे लगता है कि एक और कारण यह कोड काम नहीं कर रहा है क्योंकि एक बार जब आप नक्शे में एक उपलब्ध प्रविष्टि पाते हैं तो आप इसे उसी कुंजी (चार *) के साथ नक्शे में फिर से स्थापित करने का प्रयास करते हैं। चूँकि वह कुंजी आपके नक्शे में पहले से मौजूद है, इसलिए इंसर्ट विफल हो जाएगा। नक्शे के लिए मानक :: सम्मिलित करें () इस व्यवहार को परिभाषित करता है ... यदि कुंजी मान मौजूद है तो सम्मिलित विफल रहता है और मैप किया गया मान अपरिवर्तित रहता है। फिर वैसे भी डिलीट हो जाता है। आपको इसे पहले हटाना होगा और फिर रीस्टोर करना होगा।

यहां तक ​​कि अगर आप char * को std :: string में बदलते हैं तो भी यह समस्या बनी रहेगी।

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


0

जब मैं कई स्रोत फ़ाइलों में तत्व खोजने का प्रयास करता हूं तो मैप की कुंजी के रूप में चार * का उपयोग करने में कठिन समय था। यह ठीक काम करता है जब सभी पहुँच / खोज एक ही स्रोत फ़ाइल के भीतर होते हैं जहां तत्व डाले जाते हैं। हालांकि, जब मैं किसी अन्य फ़ाइल में खोज का उपयोग करके तत्व तक पहुंचने का प्रयास करता हूं, तो मैं उस तत्व को प्राप्त करने में सक्षम नहीं हूं जो निश्चित रूप से नक्शे के अंदर है।

यह पता चला है कि जैसा कि प्लाबो ने बताया है, पॉइंटर्स (प्रत्येक संकलन इकाई का अपना निरंतर चार * है) किसी अन्य सीपीपी फ़ाइल में एक्सेस होने पर बिल्कुल भी समान नहीं है।


0

std::map<char*,int>कुंजी की std::less<char*,int>तुलना करने के लिए डिफ़ॉल्ट का उपयोग करेगा char*, जो एक सूचक तुलना करेगा। लेकिन आप अपनी खुद की तुलना वर्ग को इस तरह निर्दिष्ट कर सकते हैं:

class StringPtrCmp {
    public:
        StringPtrCmp() {}

    bool operator()(const char *str1, const char *str2) const   {
        if (str1 == str2)
            return false; // same pointer so "not less"
        else
            return (strcmp(str1, str2) < 0); //string compare: str1<str2 ?
    }
};

std::map<char*, YourType, StringPtrCmp> myMap;

ध्यान रखें कि आपको यह सुनिश्चित करना है कि चार * सूचक वैध हैं। मैं std::map<std::string, int>वैसे भी उपयोग करने के लिए सलाह दूंगा।


-5

जब तक यह तुलना ( , ) और असाइनमेंट का समर्थन करता है <, तब तक किसी भी महत्वपूर्ण प्रकार का उपयोग करने के लिए कोई समस्या नहीं है ।>==

एक बिंदु जिसका उल्लेख किया जाना चाहिए - ध्यान रखें कि आप एक टेम्पलेट वर्ग का उपयोग कर रहे हैं । परिणाम के रूप में संकलक के लिए char*और दो अलग झटपट उत्पन्न करेगा int*। जबकि दोनों का वास्तविक कोड लगभग समान होगा।

इसलिए - मैं void*एक मुख्य प्रकार के रूप में उपयोग करने पर विचार करूंगा , और फिर आवश्यक रूप से कास्टिंग करूंगा । ये मेरा विचार हे।


8
वे कुंजी केवल समर्थन की जरूरत है <। लेकिन इसे उस तरीके से लागू करने की जरूरत है जो मददगार हो। यह संकेत के साथ नहीं है। आधुनिक संकलक समान टेम्पलेट उदाहरणों को मोड़ेंगे। (मुझे पता है कि वीसी ऐसा करता है।) मैं कभी भी उपयोग नहीं करूंगा void*, जब तक कि माप ने बहुत सारी समस्याओं को हल करने के लिए इसे नहीं दिखाया। प्रकार-सुरक्षा का त्याग कभी भी समय से पहले नहीं किया जाना चाहिए।
sbi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.