2012-11-23 6 views
1

내가 일하는 회사에서 'RestrictedMap'이라는 클래스를 만들었습니다. 이것은 표준 std :: map과 동일한 인터페이스를 제공하지만 [] 연산자는 사용할 수 없습니다. 일부 다른 기능이 클래스와 함께 편안하게 작동하도록 제공되었습니다. 내부적으로 클래스는 std :: map을 래핑합니다.std :: map 및 boost :: ptr_map 템플릿 및 상속에서 반환 값이 나 빠진다.

이제 RestrictedPointerMap이라고하는 boost :: ptr_map에 대해 동일한 작업을 수행하는 비슷한 클래스를 만들려고합니다. 이를 위해 RestrictedMapBase을 작성하여 랩핑해야하는 맵 유형을 템플릿 인수로 받아들이고 대부분의 구현을 포함합니다. 우리가 무엇을 사용했는지와 같은을 수행하고 새로운 표준 : :지도

  • RestrictedPointerMap를 래핑

    • RestrictedMap을 : 두 클래스는 포장하는 그것의 파생지도의 유형을 지정 boost :: ptr_map을 래핑합니다.

    코드는 다음과 같습니다. 클래스 완성을 위해 클래스를 단순화하지는 않았지만 나중에 관련 함수의 이름을 지정합니다.

    이 나는 ​​RestrictedPointerMap에 에게 getValue를 호출 할 경우를 제외하고, 대부분 작동

    #pragma once 
    
        #include <boost/ptr_container/ptr_map.hpp> 
        #include <boost/static_assert.hpp> 
        #include <boost/assign/list_of.hpp> 
        #include <boost/foreach.hpp> 
        #include <map> 
    
        /** 
        * Class that has the benefits of a map, but does not add an entry if it does not exists. 
        * Do not use RestrictedMapBase directly but use one of the derived classes (RestrictedMap or RestrictedPointerMap). 
        */ 
        template <typename MAP> 
        class RestrictedMapBase 
        { 
        public: 
         RestrictedMapBase(const MAP& map): 
          m_map(map) 
         {} 
    
         template<class InputIterator> 
         RestrictedMapBase(InputIterator first, InputIterator last): 
          m_map(first, last) 
         {} 
    
         RestrictedMapBase() 
         {} 
    
         /************************************************************************/ 
         /* std::map interface             */ 
         /************************************************************************/ 
    
         typedef typename MAP::iterator iterator; 
         typedef typename MAP::const_iterator const_iterator; 
         typedef typename MAP::value_type value_type; 
         typedef typename MAP::key_type key_type; 
         typedef typename MAP::mapped_type mapped_type; 
         typedef typename MAP::size_type size_type; 
    
         iterator begin() { return m_map.begin(); } 
         iterator end() { return m_map.end(); } 
         const_iterator begin() const { return m_map.begin(); } 
         const_iterator end() const { return m_map.end(); } 
         bool empty() const { return m_map.empty(); } 
         size_type size() const { return m_map.size(); } 
         iterator find(const key_type& key) { return m_map.find(key); } 
         const_iterator find(const key_type& key) const { return m_map.find(key); } 
         void clear() { m_map.clear(); } 
         void erase(iterator where) { m_map.erase(where); } 
    
         bool operator==(const typename RestrictedMapBase<MAP>& other) const { return m_map == other.m_map; } 
         bool operator!=(const typename RestrictedMapBase<MAP>& other) const { return m_map != other.m_map; } 
         bool operator<(const typename RestrictedMapBase<MAP>& other) const { return m_map < other.m_map; } 
    
         /************************************************************************/ 
         /* extra                */ 
         /************************************************************************/ 
    
         void erase(const key_type& key) 
         { 
          iterator iter(find(key)); 
          assert(found(iter)); 
          erase(iter); 
         } 
    
         void eraseIfExists(const key_type& key) 
         { 
          m_map.erase(key); 
         } 
    
         bool exists(const key_type& key) const 
         { 
          return found(find(key)); 
         } 
    
         mapped_type& getValue(const key_type& key) 
         { 
          return const_cast<mapped_type&>(static_cast<const RestrictedMapBase<MAP>&> (*this).getValue(key)); 
         } 
    
         const mapped_type& getValue(const key_type& key) const 
         { 
          const_iterator iter(find(key)); 
          assert(found(iter)); 
          return getData(iter); 
         } 
    
         mapped_type getValueIfExists(const key_type& key) const 
         { 
          BOOST_STATIC_ASSERT(boost::is_pointer<mapped_type>::value); 
          const_iterator iter(find(key)); 
          if (found(iter)) { 
          return getData(iter); 
          } else { 
          return 0; 
          } 
         } 
    
         void setValue(const key_type& key, const mapped_type& value) 
         { 
          iterator iter(find(key)); 
          assert(found(iter)); 
          setData(iter, value); 
         } 
    
         void add(const key_type& key, const mapped_type& value) 
         { 
          assert(!exists(key)); 
          insert(key, value); 
         } 
    
         void add(const RestrictedMapBase<MAP>& mapToAdd) 
         { 
          BOOST_FOREACH(value_type element, mapToAdd.m_map) 
          { 
          add(element.first, element.second); 
          } 
         } 
    
         void addOrReplace(const key_type& key, const mapped_type& value) 
         { 
          iterator iter(find(key)); 
          if (found(iter)) { 
          setData(iter, value); 
          } else { 
          insert(key, value); 
          } 
         } 
    
         mapped_type* addDefaultConstructed(const key_type& key) 
         { 
          assert(!exists(key)); 
          return &m_map[key]; 
         } 
    
        private: 
         bool found(const const_iterator& iter) const 
         { 
          return iter != end(); 
         } 
    
         const mapped_type& getData(const const_iterator& iter) const 
         { 
          return const_cast<const mapped_type&>(iter->second); 
         } 
    
         mapped_type& getData(const iterator& iter) 
         { 
          return const_cast<mapped_type&>(static_cast<const RestrictedMapBase<MAP>&>(*this).getData(iter)); 
         } 
    
         void setData(const iterator& iter, const mapped_type& value) 
         { 
          getData(iter) = value; 
         } 
    
         virtual void insert(const key_type& key, const mapped_type& value) = 0; 
    
        protected: 
         MAP& getMap() 
         { 
          return m_map; 
         } 
    
        private: 
         MAP m_map; 
        }; 
    
        template <typename KEYTYPE, typename DATATYPE> 
        class RestrictedMap: public RestrictedMapBase<std::map<KEYTYPE, DATATYPE> > 
        { 
        public: 
         RestrictedMap(const std::map<typename KEYTYPE, typename DATATYPE>& map): RestrictedMapBase(map) 
         {} 
    
         template<class InputIterator> 
         RestrictedMap(InputIterator first, InputIterator last): RestrictedMapBase(first, last) 
         {} 
    
         RestrictedMap() 
         {} 
    
         virtual void insert(const KEYTYPE& key, const DATATYPE& value) 
         { 
          getMap().insert(std::make_pair(key, value)); 
         } 
        }; 
    
        template <typename KEYTYPE, typename DATATYPE> 
        class RestrictedPointerMap: public RestrictedMapBase<boost::ptr_map<KEYTYPE, DATATYPE> > 
        { 
        public: 
         RestrictedPointerMap(const boost::ptr_map<typename KEYTYPE, typename DATATYPE>& map): RestrictedMapBase(map) 
         {} 
    
         template<class InputIterator> 
         RestrictedPointerMap(InputIterator first, InputIterator last): RestrictedMapBase(first, last) 
         {} 
    
         RestrictedPointerMap() 
         {} 
    
         virtual void insert(const KEYTYPE& key, DATATYPE* const& value) 
         { 
          /* boost::ptr_map::mapped_type does not equal the DATATYPE template parameter passed to it. Therefore this 
          * functions signature *looks* different from the RestrictedMapBase::insert signature */ 
          getMap().insert(key, std::auto_ptr<DATATYPE>(value)); 
         } 
        }; 
    

    RestrictedMap.h. getData은 올바른 값을 반환하지만 이후에는 getValue 함수에서 잘못 처리됩니다. 잘못된 포인터를 반환합니다 (포인터가 잘못됨). 여기

    문제 재생하는 코드이다

    TestClass.h을

    #pragma once 
    
        class SomeClass 
        { 
        public: 
         SomeClass(); 
         virtual ~SomeClass(); 
        }; 
    

    TestClass.cpp

    #include "stdafx.h" 
        #include "TestClass.h" 
        #include <iostream> 
    
        SomeClass::SomeClass() 
        { 
         std::cout << "TestClass[" << this << "] created." << std::endl; 
        } 
    
        SomeClass::~SomeClass() 
        { 
         std::cout << "TestClass[" << this << "] deleted." << std::endl; 
        } 
    

    TestRestrictedPtrMap.cpp (주)

    #include "stdafx.h" 
    
        #include "RestrictedMap.h" 
        #include "TestClass.h" 
        #include <boost/foreach.hpp> 
    
        int _tmain(int argc, _TCHAR* argv[]) 
        { 
         typedef RestrictedPointerMap<int, SomeClass> MapType; 
         MapType theMap; 
         theMap.add(1, new SomeClass()); 
         theMap.add(2, new SomeClass()); 
    
         BOOST_FOREACH(MapType::value_type mapEntry, theMap) { 
          std::cout << mapEntry.first << " = " << mapEntry.second << std::endl; 
         } 
    
         SomeClass* oneClass = theMap.getValue(1); 
         std::cout << oneClass << std::endl; 
         SomeClass* twoClass = theMap.getValue(2); 
         std::cout << twoClass << std::endl; 
    
         std::cin.get(); 
         return 0; 
        } 
    

    The o 이것의 utput은 다음과 같습니다 :

    TestClass[0078A318] created. 
        TestClass[0078A448] created. 
        1 = 0078A318 
        2 = 0078A448 
        0018FBD4 
        0018FBD4 
        TestClass[0078A318] deleted. 
        TestClass[0078A448] deleted. 
    

    나는 그것이 잘못되는지 전혀 모른다. 내가 아는 한 반환 값은 마술에 의해 나 빠진다. 사전에 어떤 도움

    감사합니다,

  • +0

    T 매핑 된 값을 반환하기 위해 RestrictedPointerMap의 서명을 변경하는 것이 더 나은 할 수 RestrictedMapBase &> (* this) .getValue (key));'? 그것은 저에게 거대한 의심스럽게 보입니다. –

    +0

    @DavidSchwartz : 'const'버전과 nonconst 버전 사이에서 작업을 복제하지 않는 것이 일반적인 전략입니다. 어느 쪽이라도 할 수는 있지만,'const' 버전이 아닌 오브젝트를 우연히 수정하지 않기 때문에'const' 버전 호출 (여기에 보여진 것처럼)이 더 좋습니다. 나는 Meyers의 Efficient C++에도 등장한다고 생각한다. –

    +0

    이 코드는 Frenchto와 같습니다. 내 눈 : 녹슨 것 같습니다. 어쨌든, 목표를 위해 클래스 RestrictedMapBase : public MAP을 템플릿으로 만든 다음 [] 연산자를 어떻게 든 숨 깁니다. 아마도 사적으로 만들 수도 있습니다. – kellogs

    답변

    2

    당신은 매달려 참조를 가지고있다.

    당신이 boost::ptr_map<Key, T>::iterator 역 참조는 실제 기본 반복자에서 초기화 boost::ptr_container_detail::ref_pair<Key, T *>을가 온 - 더 - 플라이 구축

    (A std::map<Key, void *>::iterator).이것은 T *& (또는 const T *&)는 로컬 임시 ( iter->secondsecond 부재)의 멤버를 참조하는 getData로부터 리턴했음을 의미

    const mapped_type& getData(const const_iterator& iter) const 
        { 
         return const_cast<const mapped_type&>(iter->second); // reference to a temporary 
        } 
                  ^^^^^^ *iter is a temporary value 
    

    *iter의 값에 대한 참조를 제공하는 일반 std::map, 상이 맵의 2 진 트리에있는 노드의 하위 오브젝트.

    메모리를 참조 할 수있는 실제 위치에 실제로 T * 개체가 없기 때문에 인터페이스를 크게 변경하지 않고도 쉬운 해결책은 없습니다.

    에 const_cast (static_cast를 반환`에서`static_cast`으로 무엇
    T *getValue(const key_type& key);    // not T *& 
    const T *getValue(const key_type& key) const; // not const T *const & 
    // or 
    T &getValue(const key_type& key);    // not T *& 
    const T &getValue(const key_type& key) const; // not const T *const &