故事从我认为非常简单的事情开始:
我需要设计一个使用某些STL容器的类。我需要让类的用户访问这些容器的不可变版本。我不希望用户能够更改容器(例如,他们不能在列表中 push_back()
),但我希望用户能够更改包含的对象(获取 back()
的元素并对其进行修改):
class Foo
{
public:
// [...]
ImmutableListWithMutableElementsType getImmutableListWithMutableElements();
// [...]
};
// [...]
myList = foo.getImmutableListWithMutableElements();
myElement = myList.back();
myElement.change(42); // OK
// [...]
// myList.push_back(myOtherElement); // Not possible
乍一看,似乎 const容器会起作用。但是,当然,您只能在 const容器上使用 const iterator ,而且您无法更改内容。
乍一看,人们会想到像专用容器或迭代器这样的东西。我可能最终会这样做。
然后,我的想法是“有人必须已经这样做了!”或“必须存在优雅,通用的解决方案!”我在这里问我关于SO的第一个问题:
如何将标准容器设计/转换为具有可变内容的不可变容器?
我正在努力,但我觉得有人会说“嘿,我每次都这样做,很容易,看!”,所以我问......
感谢您提供任何提示,建议或精彩的通用方法:)
编辑:
经过一些实验,我最终得到了处理一些特别装饰的智能指针的标准容器。它接近尼古拉的答案。
可变元素的不可变容器的概念不是一个杀戮概念,请参阅Oli回答中的有趣注释。
特定迭代器的想法当然是正确的,但它似乎不实用,因为我需要适应任何类型的容器。
感谢大家的帮助。
答案 0 :(得分:5)
您可以只为开头和结尾提供非const迭代器,而不是为用户提供整个容器吗?这是STL方式。
答案 1 :(得分:5)
最简单的选项可能是标准的STL容器指针,因为const
- ness不会传播到实际的对象。这样做的一个问题是STL不会清理您分配的任何堆内存。为此,请查看Boost Pointer Container Library或smart pointers。
答案 2 :(得分:3)
您需要一个自定义数据结构迭代器,一个围绕私有列表的包装器。
template<typename T>
class inmutable_list_it {
public:
inmutable_list_it(std::list<T>* real_list) : real_list_(real_list) {}
T first() { return *(real_list_->begin()); }
// Reset Iteration
void reset() { it_ = real_list_->begin(); }
// Returns current item
T current() { return *it_; }
// Returns true if the iterator has a next element.
bool hasNext();
private:
std::list<T>* real_list_;
std::list<T>::iterator it_;
};
答案 3 :(得分:1)
痛苦的解决方案:
/* YOU HAVE NOT SEEN THIS */
struct mutable_int {
mutable_int(int v = 0) : v(v) { }
operator int(void) const { return v; }
mutable_int const &operator=(int nv) const { v = nv; return *this; }
mutable int v;
};
对不起,我必须惩罚自己,为自己的罪赎罪。