题 有C ++懒惰指针吗?


我需要一个 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.

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


14
2018-05-18 15:00


起源




答案:


滚动你自己的努力很少。

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;

18
2018-05-18 15:24



将子包含为auto_ptr是有意义的 - Mykola Golubyev
您甚至可以使用boost :: optional <T>而不是子指针。使用boost :: optional <T>意味着您可以从堆栈分配中受益。那时没有使用堆 - Johannes Schaub - litb
此外,此自定义解决方案还需要一个复制构造函数。 - Alexander Artemenko
如何使子变量,以便const方法不会返回0? - Thomas L Holaday
@ephemient:我同意Thomas的观点 child 应该宣布 mutable。这正是那种问题 mutable 旨在解决。我的意思是,如果你想要纯粹的常量,那么像这样的类无论如何都是一个糟糕的设计,在这种情况下,我甚至认为它是不正确的! - Andreas Magnusson


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

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

将构建100个懒惰并分配一个真实 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-manual不包括赋值运算符重载。然而,消息来源确实如此。我不确定这只是手册中的缺陷还是故意遗漏其文档。所以我会使用更安全的方式使用拷贝分配 T()


10
2018-05-18 16:30



vector<LazyPtr<Box> > v(100) 将使用100 * sizeof(Box),这可能没问题,但也许OP不想为未分配的Box使用内存。由于OP没有描述更多要求,我们不知道...... - ephemient
你是对的,这是一个好点:) - Johannes Schaub - litb
是的,我不想在未分配的对象上浪费空间。 - Alexander Artemenko


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

你确定吗? 稀疏矩阵 不是你真正想要的吗?


2
2018-05-18 15:06



你为什么指向稀疏矩阵? - Mykola Golubyev
因为稀疏矩阵填充了类似(但不相同)的需求。请注意,海报的示例显示了“懒惰指针”的向量;这听起来很像稀疏矩阵。 - Dan Breslau


据我所知,目前还没有实现这类事情。虽然创建一个并不难。


0
2018-05-18 15:07