【问题标题】:Is there C++ lazy pointer?有 C++ 惰性指针吗?
【发布时间】:2009-05-18 15:00:38
【问题描述】:

我需要一个类似shared_ptr 的对象,但是当我尝试访问它的成员时它会自动创建一个真实的对象。

例如,我有:

class Box
{
public:
    unsigned int width;
    unsigned int height;
    Box(): width(50), height(100){}
};

std::vector< lazy<Box> > boxes;
boxes.resize(100);

// at this point boxes contain no any real Box object.
// But when I try to access box number 50, for example,
// it will be created.

std::cout << boxes[49].width;

// now vector contains one real box and 99 lazy boxes.

是否有一些实现,或者我应该自己编写?

【问题讨论】:

    标签: c++ pointers


    【解决方案1】:

    自己动手做起来很轻松。

    template<typename T>
    class lazy {
    public:
        lazy() : child(0) {}
        ~lazy() { delete child; }
        T &operator*() {
            if (!child) child = new T;
            return *child;
        }
        // might dereference NULL pointer if unset...
        // but if this is const, what else can be done?
        const T &operator*() const { return *child; }
        T *operator->() { return &**this; }
        const T *operator->() const { return &**this; }
    private:
        T *child;
    };
    
    // ...
    
    cout << boxes[49]->width;
    

    【讨论】:

    • 将 child 包含为 auto_ptr 是有意义的
    • 您甚至可以使用 boost::optional 代替子指针。使用 boost::optional 意味着您可以从它的堆栈分配中受益。然后不使用堆
    • 此外,此自定义解决方案需要一个复制构造函数。
    • 如何让 child 可变,这样 const 方法就不会返回 0?
    • @ehemient:我同意 Thomas 的观点,应该将 child 声明为 mutable。这正是mutable 旨在解决的问题。我的意思是,如果你想要纯常量,那么这样的类无论如何都是一个糟糕的设计,在这种情况下,我什至认为它是不正确的!
    【解决方案2】:

    使用boost::optional,你可以有这样的事情:

    // 100 lazy BigStuffs
    std::vector< boost::optional<BigStuff> > v(100);
    v[49] = some_big_stuff;
    

    将构造 100 个lazy's 并将一个真正的some_big_stuff 分配给v[49]boost::optional 将不使用堆内存,但使用placement-new 在堆栈分配的缓冲区中创建对象。我会像这样围绕boost::optional 创建一个包装器:

    template<typename T>
    struct LazyPtr {
        T& operator*() { if(!opt) opt = T(); return *opt; }
        T const& operator*() const { return *opt; }
    
        T* operator->() { if(!opt) opt = T(); return &*opt; }
        T const* operator->() const { return &*opt; }    
    private:
        boost::optional<T> opt;
    };
    

    这现在使用boost::optional 来做事。它应该支持像这样的就地构造(op* 上的示例):

    T& operator*() { if(!opt) opt = boost::in_place(); return *opt; }
    

    这不需要任何复制。但是,当前的 boost 手册不包括该赋值运算符重载。然而,消息来源确实如此。我不确定这是否只是手册中的一个缺陷,或者是否故意遗漏了它的文档。所以我会使用更安全的方式来使用T() 进行复制分配。

    【讨论】:

    • vector&lt;LazyPtr&lt;Box&gt; &gt; v(100) 将使用 100*sizeof(Box),这可能没问题,但也许 OP 不想为未分配的 Box 使用内存。由于OP没有描述更多的要求,我们不知道......
    • 对,我不想在未分配的对象上浪费空间。
    【解决方案3】:

    我从来没有听说过这样的事情,但话说回来,我从来没有听说过很多事情。 “惰性指针”如何将有用的数据放入底层类的实例中?

    您确定 sparse matrix 不是您真正想要的吗?

    【讨论】:

    • 因为稀疏矩阵可以满足类似(尽管不相同)的需求。请注意,海报的示例显示了“惰性指针”的向量;这听起来很像一个稀疏矩阵。
    【解决方案4】:

    据我所知,目前还没有这种事情的实现。不过创建一个并不难。

    【讨论】:

      猜你喜欢
      • 2012-01-11
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 2014-08-09
      相关资源
      最近更新 更多