사소한 C ++ const 관련 중복을 피하기 위해 const_cast는 작동하지만 non-const를 반환하는 개인 const 함수는 그렇지 않은 경우가 있습니까?
Scott Meyers의 Effective C ++ 항목 3에서 정적 캐스트와 결합 된 const_cast는 중복 코드를 피하는 효과적이고 안전한 방법 일 수 있다고 제안합니다.
const void* Bar::bar(int i) const
{
...
return variableResultingFromNonTrivialDotDotDotCode;
}
void* Bar::bar(int i)
{
return const_cast<void*>(static_cast<const Bar*>(this)->bar(i));
}
Meyers는 const 함수를 non-const 함수로 호출하는 것이 위험하다고 설명합니다.
아래 코드는 다음과 같은 반례입니다.
- Meyers의 제안과 달리, 때로는 정적 캐스트와 결합 된 const_cast가 위험합니다
- 때로는 const 함수가 비 const를 호출하는 것이 덜 위험합니다.
- 때로는 const_cast를 사용하는 두 가지 방법으로 잠재적으로 유용한 컴파일러 오류 숨기기
- const_cast를 피하고 추가 const 개인 멤버가 const가 아닌 것을 반환하는 것은 또 다른 옵션입니다.
코드 복제를 피하는 const_cast 전략 중 하나가 모범 사례로 간주됩니까? 대신 개인 방법 전략을 원하십니까? const_cast는 작동하지만 개인 메소드는 작동하지 않는 경우가 있습니까? 다른 옵션 (복제 외에)이 있습니까?
const_cast 전략에 대한 나의 관심은 코드를 작성할 때 코드가 정확하더라도 나중에 유지 관리 중에 코드가 잘못 될 수 있고 const_cast가 유용한 컴파일러 오류를 숨길 수 있다는 것입니다. 일반적인 개인 기능이 일반적으로 더 안전한 것 같습니다.
class Foo
{
public:
Foo(const LongLived& constLongLived, LongLived& mutableLongLived)
: mConstLongLived(constLongLived), mMutableLongLived(mutableLongLived)
{}
// case A: we shouldn't ever be allowed to return a non-const reference to something we only have a const reference to
// const_cast prevents a useful compiler error
const LongLived& GetA1() const { return mConstLongLived; }
LongLived& GetA1()
{
return const_cast<LongLived&>( static_cast<const Foo*>(this)->GetA1() );
}
/* gives useful compiler error
LongLived& GetA2()
{
return mConstLongLived; // error: invalid initialization of reference of type 'LongLived&' from expression of type 'const LongLived'
}
const LongLived& GetA2() const { return const_cast<Foo*>(this)->GetA2(); }
*/
// case B: imagine we are using the convention that const means thread-safe, and we would prefer to re-calculate than lock the cache, then GetB0 might be correct:
int GetB0(int i) { return mCache.Nth(i); }
int GetB0(int i) const { return Fibonachi().Nth(i); }
/* gives useful compiler error
int GetB1(int i) const { return mCache.Nth(i); } // error: passing 'const Fibonachi' as 'this' argument of 'int Fibonachi::Nth(int)' discards qualifiers
int GetB1(int i)
{
return static_cast<const Foo*>(this)->GetB1(i);
}*/
// const_cast prevents a useful compiler error
int GetB2(int i) { return mCache.Nth(i); }
int GetB2(int i) const { return const_cast<Foo*>(this)->GetB2(i); }
// case C: calling a private const member that returns non-const seems like generally the way to go
LongLived& GetC1() { return GetC1Private(); }
const LongLived& GetC1() const { return GetC1Private(); }
private:
LongLived& GetC1Private() const { /* pretend a bunch of lines of code instead of just returning a single variable*/ return mMutableLongLived; }
const LongLived& mConstLongLived;
LongLived& mMutableLongLived;
Fibonachi mCache;
};
class Fibonachi
{
public:
Fibonachi()
{
mCache.push_back(0);
mCache.push_back(1);
}
int Nth(int n)
{
for (int i=mCache.size(); i <= n; ++i)
{
mCache.push_back(mCache[i-1] + mCache[i-2]);
}
return mCache[n];
}
int Nth(int n) const
{
return n < mCache.size() ? mCache[n] : -1;
}
private:
std::vector<int> mCache;
};
class LongLived {};