2013-06-13 3 views
0

사용자가 시스템과의 인터페이스에 사용하는 클래스가 있습니다. 이 클래스는 내부를 숨기기 위해 Pimpl을 사용하므로 실제 구성원 만이 모든 작업을 수행하는 숨겨진 실제 객체에 대한 참조입니다.참조 의미가있는 Const 오브젝트

클래스에는 참조 의미가 있기 때문에 대개 포인터와 비슷한 값으로 전달됩니다. 이로 인해 const의 정확성 문제가 발생합니다. const 값을 const 값으로 간단히 복사하여 클래스의 특성을 매우 쉽게 깨뜨릴 수 있습니다. 전체적으로 복사를 방지하는 것보다이를 방지 할 수있는 방법이 없습니다.

개체의 const 특성을 유지하는 const 값을 반환하고 싶습니다. 없이 새로운 수업이나 새로운 수업을 만드십시오.

는 기본적으로 나는 일이 발생하지 않도록하려면 :

struct Ref 
{ 
    int &t; 
    Ref(int &_t) : t(_t) {} 
}; 

Ref MakeRef(int &t) { return Ref(t); } 

int main() 
{ 
    int foo = 5; 
    const Ref r(foo); 
    const Ref c(r);   //This should be allowed. 
    Ref other = MakeRef(foo); //This should also be allowed. 
    Ref bar(r);    //This should fail to compile somehow. 

    return 0; 
} 

모든 후, 내가 직접 한 경우에 작동하지 않을 것입니다 : 당신이 요구하는 것은 불가능하다

int &MakeRef(int &t) {return t;} 

int main() 
{ 
    int foo = 5; 
    const int &r(foo); 
    const int &c(r);   //This compiles. 
    int &other = MakeRef(foo); //This compiles. 
    int &bar(r);    //This fails to compile. 

    return 0; 
} 
+0

복사 생성자를 private으로 설정할 수 있습니다. –

+0

@JonathanPotter : 아무도 이유없이 복사 할 수 없습니다. –

+0

복사 생성자를 삭제하고 비 const 참조를 허용하는 생성자를 만드는 것은 어떨까요? – syam

답변

0

. 이 2 개 개의 라인이 다르게 작동하는 것은 불가능 :

const Ref c(r);   //This should be allowed. 
Ref bar(r);    //This should fail to compile somehow. 

두 선이 동일한 코드 경로를 통해 실행됩니다, 그들은 모두 같은 복사 생성자 (본인 또는 자동으로 생성)을 통해 실행됩니다. 유일한 차이점은 이전은 const 최종 변수가 될 것이라는 점입니다.

불행하게도 현실은 당신이 원하는 경우에 컴파일에서 위를 방지하기 위해 관리하는 경우에도, 누군가가 단순히 당신의 보호를 우회하기 위해 다음을 수행 할 수 있다는 것입니다 : 당신이 다른 것을 방지하려는 경우

const Ref c(r); 
Ref &bar = (Ref&)c; 

을 사람들이 불쾌한 일을하지 않으면 지역 변수에 대한 참조를 사용하는 대안을 찾아야합니다. 만약 당신이 자신에 대해 걱정하고 있다면 그냥하지 말아야 할 일을하지 말아라.

+0

죄송합니다. 위의 코드를 업데이트했습니다. 'Ref & bar = (Ref &)c;'는 const 객체를 const 객체의 비 const 참조로 캐스트 할 것입니다.) 예방은 없습니다 –

+0

그건 누군가가 항상 const 일 수 있기 때문에'const'-correctness가 존재하지 않는다는 것과 같습니다. (또는 C 스타일 캐스팅). int & bar (r)이 방지하는 우발적 인 오용이 아닌 고의적 인 오용입니다. –

+0

이것이 내 포인트 중 하나입니다. 왜 OP가 이것을 방지하려고합니까? 부도덕 한 사람이 자신의 안전을 우회하는 것을 막으려 고 시도하는 것입니까? –

2

const T*T* const을 정확히 섞어서 만든 것과 같은 문제이다. 참조와 참조 대상의 변경 가능성은 분명하다. . 가능한 모든 네 가지 조합에 대해 C++에서 유효한 유스 케이스가 있습니다. 나는 "CONST T 참조" "T 참조"및 대한 구별 유형을 만들 것입니다 :

#include <type_traits> 

template <typename T> 
struct Ref 
{ 
    T &t; 
    Ref(T &_t) : t(_t) {} 
    Ref(const Ref<typename std::remove_cv<T>::type>& other) : t(other.t) {} 
}; 

template <typename T> 
Ref<T> MakeRef(T& t) { return {t}; } 

template <typename T> 
Ref<const T> MakeConstRef(const T& t) { return {t}; } 

int main() 
{ 
    int foo = 5; 
    auto r = MakeConstRef(foo); 
    auto c = r;     // This is allowed. 
    auto other = MakeRef(foo); // This is also allowed. 
    Ref<const int> baz = other; // This works, too. 
    Ref<int> bar = c;   // This fails to compile, as desired. 
} 

Live example at ideone합니다.

+0

그것은 Pimpl 클래스이며, 어떤 종류의 템플릿 인수로 그것의 비공개를 노출하지 않습니다. –

+0

@NicolBolas : 요점은 이것이 가장 쉽다는 것을 의미합니다. const-to-const와 const-to-mutable에 대해 별도의 유형으로 구현할 수 있으며, 참조 가능 변환 가능으로 암시 적으로 변환 가능한 참조로 변환 할 수 있습니다. 필자는 템플릿을 사용하여 두 가지 유형의 쉬운 방법을 구현했습니다. 두 개의 명시 적 유형이 필요할 수 있습니다. ? – Casey

+0

는'심판 & 바 = (참고 &)c;는' –

0

일반적으로 CV 수정자는 클래스/구조체 정의 내에서 참조 또는 포인터를지나 이동하지 않습니다. 이것은 객체의 집합적인 부분이 아니기 때문에 기술적으로 객체를 실제로 다루는 것이 아니라 객체를 가리키는 것입니다. 당신이해야 할 것입니다 무엇

는 다음과 같이 자신의 const와 롤입니다 :

이것은 Ref::operator constRef() const 변환 기능을 통해 유형에서 const const가 아닌 간의 자동 편도 변환 할 수 있습니다
struct constRef 
{ 
    int const& _t; 
    constRef(int const& rxo) : _t(rxo) {} 
    constRef(constRef const& rxo) : _t(rxo._t) {} 

    int const & t() const { return _t; } 
    static constRef Make(int const & t) { return t; } 
}; 

struct Ref 
{ 
    int& _t; 
    Ref(int& ro) : _t(ro) {} 
    Ref(Ref const& rxo) : _t(rxo._t) {} 
    operator constRef() const { return constRef(_t); } 

    int& t() { return _t; } 
    static Ref Make(int& t) { return t; } 
}; 


int main() 
{ 
    int foo = 5; 
    Ref foo2(foo);    
    constRef r(foo2);   // non-const -> const   This compiles. 
    constRef c(r);    // const -> const    This compiles. 
    Ref other = Ref::Make(foo); // non-const -> non-const  This compiles 
    Ref bar(r);     // const -> non-const   This fails to compile 

    return 0; 
} 

. 작업 모델은 here입니다.

유일한 문제는 const 객체에 적합한 모든 유형의 작업이 서명이 복제되어야하고 body가 const 클래스의 구현을 가리킨다는 것입니다.

이 문제를 해결할 수있는 방법은 상속이 될 수 있지만 이렇게하면 컴파일러가 최적화 할 수있는 능력이 떨어지는 것은 말할 것도 없습니다.