문제

다음 코드가 주어지면 :

class foo;

foo* instance = NULL;

class foo
{
public:
   explicit foo(int j)
    : i(j)
   {
      instance = this;
   }

   void inc()
   {
      ++i;
   }

private:
   int i;
};

다음은 정의 된 동작을 사용합니까?

const foo f(0);

int main()
{
   instance->inc();
}

클래스 레지스트리를 사용하고 있기 때문에 묻고 직접 수정하지 않기 때문에 f 그것을 만드는 것이 좋을 것입니다 const, 그러나 나중에 f 레지스트리에 의해 간접적으로 수정됩니다.

편집 : 정의 된 동작에 의해 나는 의미 : 객체가 한 번만 쓸 수있는 특수 메모리 위치에 배치 되었습니까? 읽기 전용 메모리는 최소한 C ++ 1X의 ConstexPR까지 문제가되지 않습니다. 예를 들어, 일정한 원시 유형은 (종종) 읽기 전용 메모리에 배치되고 const_cast 예를 들어 다음과 같은 정의되지 않은 동작이 발생할 수 있습니다.

int main()
{
    const int i = 42;
    const_cast<int&>(i) = 0; // UB
}
도움이 되었습니까?

해결책

예, 7.1.5.1/4에 따라 정의되지 않은 동작입니다.

Mutable (7.1.1)을 선언 할 수있는 클래스 구성원을 수정할 수있는 경우를 제외하고는 수명 (3.8) 동안 Const 객체를 수정하려는 시도는 정의되지 않은 동작을 초래합니다.

물체의 수명은 생성자 호출이 완료되면 (3.8/1) 시작됩니다.

다른 팁

객체의 const 인스턴스를 정의하고 const-sness를 캐스트하고 객체의 내용을 수정하면 정의되지 않은 동작이 나타납니다.

사물의 소리에서, 당신이 원하는 것은 정확히 반대입니다. 객체의 최신 인스턴스를 작성한 다음 해당 개체에 대한 const 포인터를 클라이언트에게 (대부분)로 반환하는 반면 "소유자"는 비정규를 유지합니다. 객체에 대한 포인터는 멤버가 적합한대로 수정할 수 있습니다.

일반적으로 개인 CTOR로 클래스를 정의하여 이와 같은 상황을 관리하므로 대부분의 클라이언트는 유형의 객체를 만들 수 없습니다. 그런 다음 수업은 소유자 클래스를 친구로 선언하므로 개인 CTOR 및/또는 정적 멤버 기능을 사용하여 객체의 인스턴스 (또는 종종 하나의 인스턴스)를 생성 할 수 있습니다. 그런 다음 소유자 클래스는 고객이 사용할 수 있도록 const 객체에 포인터 (또는 참조)를 전달합니다. 객체를 수정하기 위해 "권리"가있는 소유자는 항상 객체에 대한 비정규 포인터 (또는 다시 참조)를 가지기 때문에 돌연변이가있는 멤버도 필요하지 않습니다. 클라이언트는 Const Pointers/References 만 받고 수정을 방지합니다.

이것은 잘 알려지지 않은 드문 경우 중 하나 일 수 있습니다. mutable 키워드를 사용할 수 있습니다.

mutable int i;

i 객체가 const이라도 이제 변경할 수 있습니다. 언제 사용됩니다 논리적으로 객체는 변하지 않지만 실제로는 그렇습니다.


예를 들어:

class SomeClass
{
// ....
    void DoSomething() { mMutex.lock(); ...; }
    mutable Mutex mMutex;
}

~ 안에 DoSomething() 객체는 논리적으로 변경되지는 않지만 mmutex를 잠그려면 변경해야합니다. 그래서 그것을 만드는 것이 합리적입니다 mutable, 그렇지 않으면 someclass의 사례는 없습니다 const (모든 작업에 대해 muetx를 잠그고 있다고 가정합니다).

const 객체에서 비 정기 (선언 별) 멤버 함수를 호출하는 것은 불법적이지 않습니다. 컴파일러 제한을 중심으로 작업하려는 모든 메소드를 사용할 수 있습니다. const_cast 또는 예에서와 같이 생성자가있는 트릭.

그러나 행동은 당신이 호출하는 멤버 함수가 실제로 육체적으로 시도하지 않는 한 정의됩니다. 수정하다 객체 (즉, 상수 객체의 비정상적인 멤버를 수정). 수정을 수행하려고 시도하면 동작이 정의되지 않습니다. 귀하의 경우 방법 inc 객체를 수정합니다. 즉, 예에서는 동작이 정의되지 않음을 의미합니다.

이 방법을 다시 부르는 것은 완벽하게 합법적입니다.

이러한 임의의 이름을 의도하는 것은 어렵습니다. 만약에 i 단지 사용 카운터로 의도 된 것이며 실제로 데이터의 일부로 간주되지 않으므로 다음과 같이 선언하는 것이 완벽합니다. mutable int i; 그럼 const-인스턴스의 성은 위반되지 않습니다 i 수정됩니다. 반면에 i 모델링되는 공간의 의미있는 데이터는 매우 나쁜 일입니다.

그러나 그와는 별도로, 당신의 예는 당신이 묻는 것처럼 보이는 것에 대해 약간의 혼란입니다. foo* instance = NULL; a를 사용하여 효과적으로 (혼란스럽게)입니다 NULL 숫자 제로 및 초기화 instance, 그렇지 않습니다 const; 그런 다음 별도로 초기화합니다 f, 그것은 const, 그러나 그것을 참조하지 마십시오.

GCC에 따라 적어도 생성자는 explicit foo(int j) 단어와 함께 int.

그러나 두 개의 포인터가 같은 값을 갖는 것은 완벽하게 괜찮습니다. const 그리고 다른 하나는 아닙니다.

Const 캐스트를 사용하지 않는 이유는 무엇입니까?

상태가 일정하지 않은 상태에서 객체를 만들어야 할 이유가 있습니까?

또한 다음을 변경하십시오.

explicit foo(int j = 0)    : i(j)   

{    instance = this;   }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top