2014-09-26 4 views
10

C++ 11의 임의 클래스의 임의 생성기 호출을 포함하는 상수 함수를 처리하는 올바른 방법은 무엇입니까? 함수의 상수 플래그를 포기하는 것이 더 좋을까요 아니면 생성자와 배포를 클래스의 변경 가능한 요소로 선언하는 것이 더 낫겠습니까? (컴파일되지 않음) 최소한의 예는 다음과 같을 수 있습니다상수 정확도 및 <random>

#include <random> 

class foo 
{ 
    std::mt19937 MyGenerator; 
    std::normal_distribution<precision_type> gauss; 
    double get_rnd() const {return gauss(MyGenerator);} 
}; 
+0

작은 예제를 게시 할 수 있습니까? 'random' 인스턴스가 클래스 멤버를 변경하려고 시도하지 않고 그 자체가 멤버가 아니라면 함수는 여전히'const' 상태를 유지할 수 있습니다. – CoryKramer

+4

@Cyber ​​: '임의의'인스턴스가 멤버라는 질문에 따라 (질문은 "요소"라고 말합니다). –

+3

고려 사항 중 하나는 스레드 안전성입니다. 통상은 thread 세이프로서 처리되는 Const 메소드입니다. 그래서 호출이 내부 뮤텍스에 의해 보호된다면, 나는 그것이 가변 멤버로 만들 수있는 것처럼 보입니다. 그렇지 않으면 멀티 스레딩의 약간의 기회가 관련되어있는 것처럼 보입니다. – dewaffled

답변

10

실제로 회원님의 액세스 권한은 const에 어떤 의미가 있는지에 따라 달라집니다.

표준 클래스의 경우 여러 스레드에서 동시에 const 멤버를 호출하면 스레드로부터 안전합니다. RNG가 완전히 스레드로부터 안전하지 않다면 (const 용) 멤버를 떠나서 const이 RNG를 돌연변이시킬 수 있습니다.

같은 방식으로 클래스를 디자인 할 필요는 없지만 다른 개발자는 안전하게 "읽을 수없는"클래스 (멤버 함수 const)를 동시에 검색하는 것을 혼란스럽게 느낄 것입니다.

하나의 옵션은 내부적으로 저장된 RNG를 사용하는 비 const 버전과 비 const 참조로 RNG를 허용하는 const 버전의 두 가지 변형을 제공하는 것입니다. (첫 번째 전화는 초를 부를 수 있으며, const_cast은 필요하지 않습니다.) 이것은 각각 스레드 로컬 RNG 인스턴스를 제공하는 경우 여러 스레드가 안전하게 객체를 사용할 수 있으므로 "필요한 것만 지불하십시오"지침에 따라 스레드 안전성을 구현합니다. 또한 모의 RNG 구현을 사용하여 테스트 할 수도 있습니다.

+1

제공되는 RNG를 직접 시드 할 수 있다면 (예 : 클래스 생성자를 사용하면 제공 할 수 있음), 이미 결정적이므로 모의이 없더라도 테스트는 문제가되지 않습니다. mock은 6 번째 호출이 처음에 반환되지 않는 특정 값을 반환하기를 원할 때 더욱 가치가 있습니다. –

2

mutable 키워드의 경우 이러한 유형의 위해 설계되었습니다. 랜덤 제네레이터 인스턴스 필드를이 변경자로 표시하면 동봉 클래스의 const 메소드에서도 상태가 변경 될 수 있습니다.

일반적으로 클래스의 개념 유형에 따라 회색 영역이있는 것 같습니다. 생성자의 상태가 개념적으로이 클래스의 상태와 관련이없는 경우이 솔루션보다 좋습니다. 그렇지 않으면 설계를 재고해야합니다. 발전기의 상태가 관련이 있다면 사용하는 방법이 const이 아니어야합니다.

+1

이 경우에는 좋은 생각이 아닙니다. 'mutable '은 논리적으로 'const' 메소드를 돕는 것입니다. RNG를 호출하는 것은 논리적으로 'const'가 아닙니다. –

+0

@OliverCharlesworth 그것은 좋은 지적입니다. 그러나 나는 그것이 회색 영역이고 클래스가 나타내는 개념 (응답 업데이트)에 달려 있다고 주장 할 것입니다. – BartoszKP

+0

동일한 인수가 현재 시간 또는 현재 마우스 위치를 반환하는 메서드에 적용된다고 가정합니다. – gnasher729

1

사용 사례에 따라 다르다고 생각합니다. 완전히 결정 론적 인 동작을 원한다면 클래스의 상태를 변경할 수 없도록 const 플래그를 삭제해야합니다. 그러면 변경할 필요가 없습니다. 재현성이 입증되어야하는 안전 관련 코드 또는 코드를 작성하는 경우 중요 할 수 있습니다. 정말 당신이 달성하려는 작업에 따라

6

은 일반적인 전략은 다음과 같습니다

  1. 노출 가변성을. 단순히 방법을 const으로 표시하지 마십시오.

  2. 외부화로 가변성이 노출됩니다. 메서드 매개 변수로 변경할 수있는 요소 (여기서는 생성자와 배포판)를 전달하고 내부에서 가변성을 사용하면 호출자는 모든 스레드 안전성 영향을 담당합니다.

  3. "논리"제약을 구현합니다.임의성의 사용이 클래스의 논리적 제한을 깨뜨리는 것으로 간주되지 않으면 단순히 생성자 및 배포를 mutable으로 선언 할 수 있습니다. 당신은 당신이 달성하는 의미에 따라 선택 대안

을 (다중 스레드 응용 프로그램 즉, mutable 뮤텍스를 사용하여 필요한 경우) 스레드 안전에 미치는 영향에주의.

+0

C++에서는 * Member Functions *;) –

+7

@BenVoigt : 표준은 확실하지만 구어체입니다 사용법은 "방법"을 짧은 손으로 선호하는 것처럼 보입니다. –

+3

* 방법 *이라는 용어는 컴퓨터 과학에서 의미가 있습니다. C++에서 무차별 적으로 적용하는 사용자는 메소드를 가지고있는 Java에서 왔으며 C++ 멤버 함수가 기본값에 의한 가상 함수가 아니라는 것을 알아 냈습니다. . –