具有可变内容的不可变容器

时间:2011-01-25 18:38:25

标签: c++

故事从我认为非常简单的事情开始:

我需要设计一个使用某些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回答中的有趣注释。

特定迭代器的想法当然是正确的,但它似乎不实用,因为我需要适应任何类型的容器。

感谢大家的帮助。

4 个答案:

答案 0 :(得分:5)

您可以只为开头和结尾提供非const迭代器,而不是为用户提供整个容器吗?这是STL方式。

答案 1 :(得分:5)

最简单的选项可能是标准的STL容器指针,因为const - ness不会传播到实际的对象。这样做的一个问题是STL不会清理您分配的任何堆内存。为此,请查看Boost Pointer Container Librarysmart 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;
};

对不起,我必须惩罚自己,为自己的罪赎罪。