তুচ্ছ সি ++ কনট সম্পর্কিত নকল এড়ানোর জন্য, এমন কোনও ঘটনা রয়েছে যেখানে কনস্ট_কাস্ট কাজ করবে তবে একটি বেসরকারী কনস্ট ফাংশন নন-কনস্ট্যান্টকে ফেরত দেবে না?
স্কট মায়ার্স এর কার্যকর সি ++ আইটেম 3 এ তিনি পরামর্শ দিয়েছেন যে একটি স্ট্যাটিক কাস্টের সাথে মিলিত একটি কনস্ট_কাস্ট ডুপ্লিকেট কোড এড়াতে কার্যকর এবং নিরাপদ উপায় হতে পারে, যেমন
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));
}
মায়াররা আরও ব্যাখ্যা করে যে কনস্ট্যান্ড ফাংশনটিকে নন-কনস্ট্যান্ট ফাংশন কল করা বিপজ্জনক।
নীচের কোডটি একটি পাল্টা উদাহরণ দেখাচ্ছে:
- মায়ারদের পরামর্শের বিপরীতে, কখনও কখনও স্থির কাস্টের সাথে মিলিত কনস্ট_কাস্ট বিপজ্জনক হয়
- কখনও কখনও কনস্টের ফাংশনটি নন-কনস্ট্যান্ট করা কম বিপজ্জনক হয়
- কখনও কখনও উভয় উপায়ে একটি কনস্টেস্ট ব্যবহার করে সম্ভাব্য কার্যকর সংকলক ত্রুটিগুলি লুকান
- কোনও কনস্ট্যান্ট কাস্টম এড়ানো এবং অতিরিক্ত কনস্টেটের ব্যক্তিগত সদস্যকে নন-কনস্ট্যান্ট ফিরিয়ে দেওয়া অন্য বিকল্প is
কোড ডুপ্লিকেশন এড়ানোর কনস্ট_কাস্ট কৌশলগুলির মধ্যে কোনটিই ভাল অনুশীলন হিসাবে বিবেচিত হয়? আপনি কি পরিবর্তে ব্যক্তিগত পদ্ধতি কৌশল পছন্দ করবেন? কনস্ট_কাস্ট কাজ করবে এমন কোনও মামলা আছে তবে একটি ব্যক্তিগত পদ্ধতি কাজ করে না? অন্যান্য অনুলিপি আছে (নকল ছাড়াও)?
কনস্ট_কাস্ট কৌশলগুলির সাথে আমার উদ্বেগটি হ'ল কোডটি লেখার সময় সঠিক হলেও, পরে রক্ষণাবেক্ষণের সময় কোডটি ভুল হতে পারে এবং কনস্ট_কাস্ট একটি কার্যকর সংকলক ত্রুটিটি আড়াল করে। দেখে মনে হচ্ছে একটি সাধারণ ব্যক্তিগত কাজটি সাধারণত নিরাপদ।
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 {};