Boost 常量列表,非常量元素访问

Boost 常量列表,非常量元素访问,boost,constants,containers,Boost,Constants,Containers,我对boost入侵容器有一个问题 我的一个类有一些对象的入侵列表,这些对象的生存期由它严格管理。对象本身应该由类的用户修改,但它们不应该修改列表本身。这就是为什么我只通过“getList”函数提供对列表的访问,该函数返回侵入列表的const版本 const入侵列表的问题是,当您尝试遍历元素时,它们也会变成const。但是用户应该能够迭代并修改这些项目 我不想为用户保留一个单独的指针列表,因为这会使使用侵入式容器的最大优势之一失效。也就是说,能够在固定时间内从容器中删除项,而您唯一拥有的是指向该项

我对boost入侵容器有一个问题

我的一个类有一些对象的入侵列表,这些对象的生存期由它严格管理。对象本身应该由类的用户修改,但它们不应该修改列表本身。这就是为什么我只通过“getList”函数提供对列表的访问,该函数返回侵入列表的const版本

const入侵列表的问题是,当您尝试遍历元素时,它们也会变成const。但是用户应该能够迭代并修改这些项目

我不想为用户保留一个单独的指针列表,因为这会使使用侵入式容器的最大优势之一失效。也就是说,能够在固定时间内从容器中删除项,而您唯一拥有的是指向该项的指针


如果因为C++的限制而不得不给出我的列表的非永久版本,那将是令人悲哀的。所以问题是:boost入侵容器是否有一个特殊的const版本,它神奇地允许对项目进行修改,同时不允许对列表本身进行任何修改

您不需要返回列表,只需通过引用访问单独的项目

好的,我已经为这个问题设计了一个完整的解决方案。如果您不需要以有效的方式迭代项目,Andy的解决方案很好。但是我想要一些语义上等同于const std::list的东西。也许这有点过分,但在性能方面,优化后几乎没有什么区别:

解决方案是使用一个名为ConstList的类私下扩展入侵列表,该类的公开程度仅足以让BOOST_FOREACH进行迭代,但任何人都不会进行任何更改。我已将列表挂钩从item移动到子类,因此item对象也不能用于更改列表。我们用钩子存储子类,但迭代器返回对item类的引用。我已将此解决方案编码为两个模板类,以便轻松应用于任何项目类

我用ConstList类和HookedItem类创建了一个头文件,后面是tests.cpp,用于测试和基准测试。您将看到我们的ConstList类在迭代时具有相同的性能

它工作得非常干净,用户代码也保持干净。然后这就引出了一个问题:为什么它还没有在boost中呢

可以出于任何目的随意使用以下代码:)

附言:在提出这个解决方案的时候,我得到了一些启示:“const”不过是一种语法糖,它是一种特殊情况下的糖,您可以通过正确的类层次结构实现它。这是真的,还是我过度概括了

------------------ConstList.h-----------------------

#include <boost/intrusive/list_hook.hpp>

template < typename T>
struct type_wrapper{  typedef T type;};

template<class listType, class owner, class item>
class ConstList: private listType {
    friend class type_wrapper<owner>::type;
public:
    class iterator {
        typename listType::iterator it;
    public:
        typedef std::forward_iterator_tag iterator_category;
        typedef item value_type;
        typedef int difference_type;
        typedef item* pointer;
        typedef item& reference;
        template<class T>
        iterator(const T it): it(it){}
        bool operator==(iterator & otherIt) {return it==otherIt.it;}
        iterator & operator++() {
            it++;
            return *this;
        }
        item & operator*() {
            return *it;
        }
    };
    iterator begin() {
        return iterator(listType::begin());
    }

    iterator end() {
        return iterator(listType::end());
    }
};

template<class item, class owner, class hooktype>
class HookedItem: public item {
    friend class type_wrapper<owner>::type;
public:
    hooktype hook_;
    typedef boost::intrusive::member_hook<HookedItem, hooktype, &HookedItem::hook_> MemberHookOption;
private:
    template<class Arg1, class Arg2>
    HookedItem(Arg1 &arg1, Arg2 &arg2): item(arg1, arg2){}
};
#include<cstdio>
#include<boost/checked_delete.hpp>
#include<ConstList.h>
#include<boost/intrusive/list.hpp>
#include<boost/foreach.hpp>

using namespace boost::intrusive;

class myOwner;
class myItem {
public:
    int a,b; //arbitrary members
    myItem(int a, int b): a(a), b(b){};
};

typedef HookedItem<myItem,myOwner,list_member_hook<> > myHookedItem;
typedef list<myHookedItem, typename myHookedItem::MemberHookOption> myItemList;
typedef ConstList<myItemList,myOwner,myItem> constItemList;

class myOwner {
public:
    constItemList constList;
    myItemList & nonConstList;
    myOwner(): nonConstList(constList) {}
    constItemList & getItems() { return constList;}
    myItem * generateItem(int a, int b) {
        myHookedItem * newItem = new myHookedItem(a,b);
        nonConstList.push_back(*newItem);
        return newItem;
    }
    ~myOwner() {nonConstList.clear_and_dispose(boost::checked_delete<myHookedItem>);}
};


int main(int argc, char **argv) {
    myOwner owner;
    int avoidOptimization=0;
    for(int i=0; i<1000000; i++) {
        owner.generateItem(i,i);
    }


    clock_t start = clock();
    for(int i=0; i<1000; i++)
        BOOST_FOREACH(myItem & item, owner.constList)
            avoidOptimization+=item.a;
    printf ( "%f\n", ( (double)clock() - start ) / CLOCKS_PER_SEC );


    start = clock();
    for(int i=0; i<1000; i++)
        BOOST_FOREACH(myHookedItem & item, owner.nonConstList)
            avoidOptimization+=item.a;
    printf ( "%f\n", ( (double)clock() - start ) / CLOCKS_PER_SEC );


    printf ("%d",avoidOptimization);
    return 0;
}
4.690000
4.700000
1764472320

这是一个非常好的答案,实际上,我正在从stl指针列表切换到侵入式列表,这就是为什么我的思维一直停留在返回列表上。此解决方案会产生一个问题,即用户将能够使用非常量项本身修改列表。有解决方案吗?好的,我已经考虑了以下通过项操纵列表的可能性的解决方案:我将有一个“itemBase”类,它没有列表挂钩,并通过引用用户来传递它的实例。而我的类的列表将保留类“item”的对象,该类只从itemBase和list hook继承。这有意义吗,还是我忽略了什么?是的,听起来不错。还有另一个选项(我假设您使用
base hook
):从
list\u base\u hook
中私下派生,并在
Item
中将
boost::intrusive::list
声明为好友。仅仅与boost::intrusive::list交朋友似乎没有帮助。我仍然得到错误:“boost::intrusive::detail::node\u holder”是许多其他东西中无法访问的“node”基。您可以找到哪些boost类需要访问
list\u base\u hook
,并将其添加为好友(使用
boost::intrusive::list
或替代它)。只有当您不喜欢最初提供单独的基类来限制访问的方法时,才可以这样做