2010-03-17 3 views
7

이 질문은 일반적으로 C++과 관련하여보다 적절하게 질문 할 수 있지만, 리눅스에서 gcc를 사용하고 있기 때문에 그 맥락입니다. 다음의 프로그램을 고려 : 프로그램을 실행하면C++ : 연산자 []에 액세스 할 때 const 대신 const가 아닌 gcc를 사용하는 이유는 무엇입니까?

#include <iostream> 
#include <map> 
#include <string> 

using namespace std; 

template <typename TKey, typename TValue> 
class Dictionary{ 
    public: 
    map<TKey, TValue> internal; 

    TValue & operator[](TKey const & key) 
    { 
     cout << "operator[] with key " << key << " called " << endl; 
     return internal[key]; 
    } 

    TValue const & operator[](TKey const & key) const 
    { 
     cout << "operator[] const with key " << key << " called " << endl; 
     return internal.at(key); 
    } 

}; 

int main(int argc, char* argv[]) 
{ 
    Dictionary<string, string> dict; 
    dict["1"] = "one"; 
    cout << "first one: " << dict["1"] << endl; 

    return 0; 
} 

을, 출력은 : 내가 좋아하는 것이 무엇

operator[] with key 1 called 
    operator[] with key 1 called 
    first one: one 

컴파일러가 두 번째 호출에 대신 operator[]const 방법을 선택하는 것입니다. 그 이유는 이전에 dict [ "1"]을 사용하지 않고 operator[]을 호출하면 존재하지 않는 데이터를 내부 맵으로 생성하기 때문에 원하는 것은 디버깅 출력을하는 것이었기 때문입니다. 치명적인 응용 프로그램 오류.

나는 GET과 세트 작업과 장소 게터가 존재하지 않는 무언가에 액세스하려고하는 경우는 예외를 던질 수있는 C#을 인덱스 연산자 같은 것입니다 찾고 있어요 동작 :

class MyDictionary<TKey, TVal> 
{ 
    private Dictionary<TKey, TVal> dict = new Dictionary<TKey, TVal>(); 
    public TVal this[TKey idx] 
    { 
     get 
     { 
      if(!dict.ContainsKey(idx)) 
       throw KeyNotFoundException("..."); 

      return dict[idx]; 
     } 
     set 
     { 
      dict[idx] = value; 
     } 
    } 
} 

그래서 const가 아닌 액세스가 필요하지 않을 때 gcc가 const 호출을 통해 non-const 호출을 선호하는지 궁금합니다.

답변

0

해당 클래스의 const 개체를 인스턴스화 할 경우 const 메서드를 사용합니다.

1

원하는 효과를 얻을 수 없습니다. dict가 const가 아닌 경우, operator []의 비 const 버전을 호출합니다.

이 경우 dict [n]이 할당의 일부인지 여부를 판단 할 수 있기 때문에 C#이 우수합니다. C++은 이것을 할 수 없습니다.

+0

사용할 수있는 버전이 const이고 "폐기 규정 자"오류가 발생하지 않는 한 비 const를 호출합니다. 분명히 컴파일러는 어떤 버전이 존재하는지 알기 때문에 내 데이터를 파괴하지 않는 버전을 사용할 수 있습니다. 필자는 개인적으로 이것이 나쁜 컴파일러 동작이라고 생각하므로 저를 계몽하십시오. 다른 방법으로 비 const를 선호하는 것이 더 안전한 AFAICT 일 때 왜이 방법으로이 작업을 수행 했습니까? – JonasW

+3

은 더 안전 해 보일지 모르지만 너무 논리적이지는 않습니다. * 최고 * 일치는 정확히 동일한 유형 및 constness이므로 비 const 하나입니다. 그 후에 다른 성냥을 찾을 수 있습니다. 일반적으로이 결과는 놀랄 일이 아닙니다. 안전을 원하는 경우, 그것을 사용하도록 지시해야합니다. –

0

모든 C++ 컴파일러는 이러한 방식으로 작동해야합니다. 함수가 대입 연산자의 왼쪽 또는 오른쪽에 나타날지 여부에 따라 과부하를 선택할 수 없습니다. 과부하는 인스턴스가 const인지 여부에 따라 선택됩니다.

C#의 속성과 C++의 메서드 const를 기반으로하는 오버로드는 다른 목적으로 사용되는 여러 가지 일들 일뿐입니다. 질문이 Why can't we have an immutable version of operator[] for map 관련이 있는지


내가 궁금해?

할당의 왼쪽 부분과 다른 부분에서 프록시 클래스를 사용하는 것을 구분할 수 있습니다 (이 용어가 옳기를 바랍니다). 그러나 실제로는 너무 잘 작동하지 않습니다. 암시 적 변환 연산자 (암시 적 변환이 필요한 결과를 출력한다는 점에 유의하십시오) 때문에이 값을 권장하지 않습니다.

#include <iostream> 
#include <map> 
#include <string> 
#include <stdexcept> 

using namespace std; 

template <typename KeyType, typename ValueType> 
class DictProxy; 

template <typename KeyType, typename ValueType> 
class ConstDictProxy; 

template <typename TKey, typename TValue> 
class Dictionary{ 
    public: 
    map<TKey, TValue> internal; 

    DictProxy<TKey, TValue> operator[](TKey const & key); 
    ConstDictProxy<TKey, TValue> operator[](TKey const & key) const; 
}; 

template <typename KeyType, typename ValueType> 
class DictProxy 
{ 
    std::map<KeyType, ValueType>* p_map; 
    const KeyType* key; 
    DictProxy(std::map<KeyType, ValueType>* p_map, const KeyType* key): p_map(p_map), key(key) {} 
    friend class Dictionary<KeyType, ValueType>; 
public: 
    void operator=(const ValueType& value) const { 
     cout << "operator[] used on the left side of assignment with key " << *key << endl; 
     (*p_map)[*key] = value; 
    } 
    operator ValueType&() const { 
     cout << "operator[] used in a different context with " << *key << endl; 

     //you used at here 
     //it is in the C++0x standard, but generally not in online references? 
     typename std::map<KeyType, ValueType>::iterator it = p_map->find(*key); 
     if (it == p_map->end()) { 
      throw std::range_error("Missing key in map"); 
     } 
     return it->second; 
    } 
}; 

template <typename KeyType, typename ValueType> 
class ConstDictProxy 
{ 
    const std::map<KeyType, ValueType>* p_map; 
    const KeyType* key; 
    ConstDictProxy(const std::map<KeyType, ValueType>* p_map, const KeyType* key): p_map(p_map), key(key) {} 
    friend class Dictionary<KeyType, ValueType>; 
public: 
    operator const ValueType&() const { 
     cout << "operator[] const used in a different context with " << *key << endl; 
     typename std::map<KeyType, ValueType>::const_iterator it = p_map->find(*key); 
     if (it == p_map->end()) { 
      throw std::range_error("Missing key in map"); 
     } 
     return it->second; 
    } 
}; 

template <typename TKey, typename TValue> 
DictProxy<TKey, TValue> Dictionary<TKey, TValue>::operator[](TKey const & key) 
{ 
    return DictProxy<TKey, TValue>(&internal, &key); 
} 

template <typename TKey, typename TValue> 
ConstDictProxy<TKey, TValue> Dictionary<TKey, TValue>::operator[](TKey const & key) const 
{ 
    return ConstDictProxy<TKey, TValue>(&internal, &key); 
} 

int main(int argc, char* argv[]) 
{ 
    Dictionary<string, string> dict; 
    dict["1"] = "one"; 
    cout << "first one: " << string(dict["1"]) << endl; 

    const Dictionary<string, string>& r_dict = dict; 
    cout << "first one: " << string(r_dict["1"]) << endl; 
    return 0; 
} 

(일부 코드 재사용은 DictProxy 및 ConstDictProxy을 구현할 때 DRY를 repect 할 수 있어야한다.) 질문이 그와 관련이있는 경우


그러나 한 후 용액이 IMO at()을 사용하는 것입니다 방법을 사용하면 기본 값을 추가하지 않으려 고 할 때 operator[]을 입력하십시오. 나는 이전에 C++ 0x가 추가 된 것으로 의심합니다.

+0

시간 내 주셔서 감사합니다. 나는 오늘 밤 이것을 보게 될 것이다. – JonasW

0

C++에서 당신이 담당하고 결정을 내리는 것을 기억하십시오.

비 const 연산자에서 원하는 경우 개체를 변경할 수 있습니다. 네가하지 않는다는 것이 단지 일어난다. 코더는 객체를 변경할지 여부를 완전히 임의로 선택할 수 있습니다. 컴파일러는 의도가 무엇인지 알지 못합니다. 즉, 컴파일러가 const를 사용하는 것을 알기에 좋은 규칙은 없습니다.

그래서 예 .... 컴파일러에게 무엇을 const로 처리할지 알려줍니다.

관련 문제