There are a number of obvious problems with this class and it is meant to illustrate the problem rather than demonstrate working code.
#include <list>
template<typename T>
class OnlyLists {
private:
const std::list<T>* p_list;
public:
OnlyLists(std::list<T>* list) : p_list(list) { }
OnlyLists(const std::list<T>* list) : p_list(list) { }
void modifiesList() {
const_cast<std::list<T>*>(p_list)->clear();
}
size_t viewsList() const {
return p_list->size();
}
};
int main() {
const std::list<int> const_list;
// Constness is preserved
const OnlyLists<int> a(&const_list);
// Constness is discarded
OnlyLists<int> b(&const_list);
// Constness is discarded (another inherited problem)
b = a;
return 0;
}
I want to create a class that can view and modify a particular object (a list in this example). Its methods are exposed such that only the const
ones can modify the list. The problem is that this constness on the methods only relates to whether the OnlyLists
object is const
. And if I accept a const list<T>*
without also declaring the OnlyLists
object as const
then I can modify the list when I shouldn't.
It's possible to work around this by making the constructors private and making object creation a static method to ensure constness but this approach throws away public constructors entirely and is instead an anti-pattern. Additionally, keeping only one pointer p_list
would already requires constness to be cast away when calling any method that would modify the list.
What is the correct pattern in C++ where I want one class to be able to view and modify another object like this?
The only solution that I can see is that any class which accepts both const
and non-const types can only provide a const view. But the only issue here is with the object construction; the actual interface already protects the object from modification.
I thought about moving the entire list
type into the template but this seems redundant if the class already accepts only lists. If I move the entire container into the template then constraints would need to be added to ensure that it is a list, etc. This seems overly complex when the constructor already limits itself to accepting only lists.
Aucun commentaire:
Enregistrer un commentaire