जब कोई कुंजी मौजूद नहीं होती है तो क्या डिफ़ॉल्ट मूल्य std::map
के operator[]
रिटर्न को निर्दिष्ट करने का कोई तरीका है?
जवाबों:
नहीं, वहाँ नहीं है। सबसे सरल उपाय यह करने के लिए अपने स्वयं के निशुल्क टेम्पलेट फ़ंक्शन को लिखना है। कुछ इस तरह:
#include <string>
#include <map>
using namespace std;
template <typename K, typename V>
V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval ) {
typename std::map<K,V>::const_iterator it = m.find( key );
if ( it == m.end() ) {
return defval;
}
else {
return it->second;
}
}
int main() {
map <string,int> x;
...
int i = GetWithDef( x, string("foo"), 42 );
}
C ++ 11 अद्यतन
उद्देश्य: सामान्य सहयोगी कंटेनरों के साथ-साथ वैकल्पिक तुलनित्र और आवंटन मापदंडों के लिए खाता।
template <template<class,class,class...> class C, typename K, typename V, typename... Args>
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval)
{
typename C<K,V,Args...>::const_iterator it = m.find( key );
if (it == m.end())
return defval;
return it->second;
}
operator[]
डिफ़ॉल्ट मान के साथ सटीक व्यवहार प्रदान करने के लिए , डिफ़ॉल्ट मान को if ( it == m.end() )
ब्लॉक के अंदर के मानचित्र में डाला जाना चाहिए
हालांकि यह इस सवाल का बिल्कुल जवाब नहीं देता है, मैंने समस्या को इस तरह कोड के साथ दरकिनार कर दिया है:
struct IntDefaultedToMinusOne
{
int i = -1;
};
std::map<std::string, IntDefaultedToMinusOne > mymap;
C ++ मानक (23.3.1.2) निर्दिष्ट करता है कि नव सम्मिलित मूल्य डिफ़ॉल्ट रूप से निर्मित है, इसलिए map
स्वयं इसे करने का एक तरीका प्रदान नहीं करता है। आपकी पसंद हैं:
operator[]
उस डिफ़ॉल्ट को सम्मिलित करने के लिए लागू करता है ।अधिक सामान्य संस्करण, समर्थन C ++ 98/03 और अधिक कंटेनर
सामान्य सहयोगी कंटेनरों के साथ काम करता है, एकमात्र टेम्पलेट पैरामीटर कंटेनर प्रकार ही है।
समर्थित कंटेनर: std::map
, std::multimap
, std::unordered_map
, std::unordered_multimap
, wxHashMap
, QMap
, QMultiMap
, QHash
, QMultiHash
, आदि
template<typename MAP>
const typename MAP::mapped_type& get_with_default(const MAP& m,
const typename MAP::key_type& key,
const typename MAP::mapped_type& defval)
{
typename MAP::const_iterator it = m.find(key);
if (it == m.end())
return defval;
return it->second;
}
उपयोग:
std::map<int, std::string> t;
t[1] = "one";
string s = get_with_default(t, 2, "unknown");
यहाँ एक आवरण वर्ग का उपयोग करके एक समान कार्यान्वयन है, जो कि पायथन में विधि get()
के dict
प्रकार के समान है : https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_nils.hpp
template<typename MAP>
struct map_wrapper
{
typedef typename MAP::key_type K;
typedef typename MAP::mapped_type V;
typedef typename MAP::const_iterator CIT;
map_wrapper(const MAP& m) :m_map(m) {}
const V& get(const K& key, const V& default_val) const
{
CIT it = m_map.find(key);
if (it == m_map.end())
return default_val;
return it->second;
}
private:
const MAP& m_map;
};
template<typename MAP>
map_wrapper<MAP> wrap_map(const MAP& m)
{
return map_wrapper<MAP>(m);
}
उपयोग:
std::map<int, std::string> t;
t[1] = "one";
string s = wrap_map(t).get(2, "unknown");
C ++ 17 प्रदान करता है try_emplace
जो वास्तव में ऐसा करता है। यह मान निर्माणकर्ता के लिए एक कुंजी और एक तर्क सूची लेता है और एक जोड़ी देता है: iterator
a bool
: a ।: Http://en.cppreference.com/w/cpp/container/map/try_emplace
डिफ़ॉल्ट मान निर्दिष्ट करने का कोई तरीका नहीं है - यह हमेशा डिफ़ॉल्ट (शून्य पैरामीटर कंस्ट्रक्टर) द्वारा निर्मित मूल्य है।
वास्तव में operator[]
संभवतः आपकी अपेक्षा से अधिक होता है जैसे कि मानचित्र में दी गई कुंजी के लिए कोई मान मौजूद नहीं है, यह डिफ़ॉल्ट कंस्ट्रक्टर से मान के साथ एक नया सम्मिलित करेगा।
find
जो किसी दिए गए कुंजी के लिए कोई तत्व मौजूद होने पर अंतिम पुनरावृत्ति वापस नहीं करता है।
find
उस मामले में समय की जटिलता कितनी है ?
template<typename T, T X>
struct Default {
Default () : val(T(X)) {}
Default (T const & val) : val(val) {}
operator T & () { return val; }
operator T const & () const { return val; }
T val;
};
<...>
std::map<KeyType, Default<ValueType, DefaultValue> > mapping;
मान का उपयोग डिफ़ॉल्ट निर्माणकर्ता द्वारा किया जाता है, जैसा कि अन्य उत्तर कहते हैं। हालाँकि, यह जोड़ना उपयोगी है कि साधारण प्रकार (इंटीग्रल टाइप जैसे इंट, फ्लोट, पॉइंटर या पीओडी (प्लान पुराने डेटा) प्रकार) के मामले में, मान शून्य-आरंभीकृत होते हैं (या मूल्य-आरंभीकरण द्वारा शून्य होते हैं (जो प्रभावी रूप से होते हैं) एक ही चीज), C ++ के किस संस्करण पर निर्भर करता है)।
वैसे भी, लब्बोलुआब यह है कि सरल प्रकार के नक्शे नए आइटमों को स्वचालित रूप से शून्य-आरंभ करेंगे। इसलिए कुछ मामलों में, डिफ़ॉल्ट प्रारंभिक मूल्य को स्पष्ट रूप से निर्दिष्ट करने के बारे में चिंता करने की कोई आवश्यकता नहीं है।
std::map<int, char*> map;
typedef char *P;
char *p = map[123],
*p1 = P(); // map uses the same construct inside, causes zero-initialization
assert(!p && !p1); // both will be 0
देखें कि क्या प्रकार के नाम के बाद कोष्ठक नए के साथ अंतर करते हैं? मामले पर अधिक जानकारी के लिए।
map::at()
इसके बजाय एक वर्कअराउंड का उपयोग करना है []
। यदि कोई कुंजी मौजूद नहीं है, तो at
एक अपवाद फेंकता है। यहां तक कि अच्छे, यह वैक्टर के लिए भी काम करता है, और इस प्रकार जेनेरिक प्रोग्रामिंग के लिए अनुकूल है जहां आप वेक्टर के साथ मानचित्र को स्वैप कर सकते हैं।
अपंजीकृत कुंजी के लिए एक कस्टम मान का उपयोग करना खतरनाक हो सकता है क्योंकि कस्टम मूल्य (जैसे -1) को कोड में और नीचे संसाधित किया जा सकता है। अपवादों के साथ, बग को स्पॉट करना आसान है।
हो सकता है कि आप एक कस्टम आवंटनकर्ता दे सकते हैं जो आप चाहते हैं कि डिफ़ॉल्ट मान के साथ आवंटित करें।
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
operator[]
कोई वस्तु T()
जो आबंटक द्वारा की जाती है , को लागू करके बनाई गई वस्तु को लौटाती है।
construct
पद्धति को नहीं बताता है ? मुझे लगता है कि इसे बदलना संभव होगा। मुझे construct
उस फ़ंक्शन पर संदेह है जो कुछ और से अलग new(p) T(t);
नहीं है, हालांकि यह अच्छी तरह से गठित नहीं है, हालांकि। संपादित करें: मूर्खता में, जो मूर्ख था, अन्यथा सभी मूल्य समान होंगे: पी कहां है मेरी कॉफी ...
operator[]
लौटती है (*((insert(make_pair(x, T()))).first)).second
। इसलिए जब तक मुझे कुछ याद नहीं आ रहा है, यह जवाब गलत है।
insert
में एक के साथ करता है T()
, लेकिन अंदर है जब यह एक नई के लिए आवंटन प्राप्त स्मृति का उपयोग करेगा T
तब construct
उस मेमोरी पर कॉल करें जिस पैरामीटर के साथ यह दिया गया था, जो है T()
। इसलिए वास्तव में यह संभव है कि व्यवहार को बदलने के operator[]
लिए इसे कुछ और लौटाया जाए, लेकिन आवंटनकर्ता इसे अलग नहीं कर सकता कि इसे क्यों कहा जा रहा है। इसलिए भले ही हमने construct
इसे अनदेखा कर दिया हो, लेकिन यह पैरामीटर का उपयोग करता है और हमारे विशेष मूल्य का उपयोग करता है, इसका मतलब है कि प्रत्येक निर्मित तत्व में वह मूल्य होता है, जो खराब है।
Https://stackoverflow.com/a/2333816/272642 के उत्तर पर विस्तार करते हुए , यह टेम्प्लेट फंक्शन टाइप करने के लिए और टाइप करने के लिए std::map
's' key_type
और ' mapped_type
typeedefs ' का उपयोग करता है । यह इन typedefs के बिना कंटेनरों के साथ काम नहीं करता है।key
def
template <typename C>
typename C::mapped_type getWithDefault(const C& m, const typename C::key_type& key, const typename C::mapped_type& def) {
typename C::const_iterator it = m.find(key);
if (it == m.end())
return def;
return it->second;
}
यह आपको उपयोग करने की अनुमति देता है
std::map<std::string, int*> m;
int* v = getWithDefault(m, "a", NULL);
जैसे तर्क देने की आवश्यकता के बिना std::string("a"), (int*) NULL
।
का उपयोग करें std::map::insert()
।
यह महसूस करते हुए कि मुझे इस पार्टी में काफी देर हो चुकी है, लेकिन यदि आप operator[]
कस्टम डिफॉल्ट्स के साथ व्यवहार में रुचि रखते हैं (अर्थात, दिए गए कुंजी के साथ तत्व को ढूंढें, यदि वह मौजूद नहीं है तो मैप में एक तत्व डालें डिफ़ॉल्ट मान चुना गया है और या तो नए सम्मिलित मूल्य या मौजूदा मूल्य का संदर्भ लौटाता है), C ++ 17 से पहले ही आपके पास एक फ़ंक्शन उपलब्ध है std::map::insert()
:। insert
यदि कुंजी पहले से मौजूद है, तो वास्तव में सम्मिलित नहीं करेंगे, बल्कि मौजूदा मान में एक पुनरावृत्तिकर्ता को लौटा देंगे।
कहो, आप स्ट्रिंग-टू-इंट का एक नक्शा चाहते थे और यदि कुंजी अभी तक मौजूद नहीं थी, तो 42 का डिफ़ॉल्ट मान सम्मिलित करता है:
std::map<std::string, int> answers;
int count_answers( const std::string &question)
{
auto &value = answers.insert( {question, 42}).first->second;
return value++;
}
int main() {
std::cout << count_answers( "Life, the universe and everything") << '\n';
std::cout << count_answers( "Life, the universe and everything") << '\n';
std::cout << count_answers( "Life, the universe and everything") << '\n';
return 0;
}
जिसमें 42, 43 और 44 का उत्पादन होना चाहिए।
यदि मानचित्र मान के निर्माण की लागत अधिक है (यदि कुंजी को कॉपी करना / स्थानांतरित करना या मूल्य प्रकार महंगा है), तो यह एक महत्वपूर्ण प्रदर्शन दंड के रूप में आता है, जो मुझे लगता है कि C ++ 17 के साथ परिवृत्त होगा try_emplace
।