有C++懒惰指针吗?

Ale*_*nko 14 c++ pointers

我需要一个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.
Run Code Online (Sandbox Code Playgroud)

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

eph*_*ent 18

滚动你自己的努力很少.

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;
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*itb 10

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

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

将建设100级懒惰的,并分配一个真实some_big_stuffv[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;
};
Run Code Online (Sandbox Code Playgroud)

这现在boost::optional用于做东西.它应该像这样支持就地构造(示例op*):

T& operator*() { if(!opt) opt = boost::in_place(); return *opt; }
Run Code Online (Sandbox Code Playgroud)

这不需要任何复制.但是,当前的boost-manual不包括赋值运算符重载.然而,消息来源确实如此.我不确定这只是手册中的缺陷还是故意遗漏其文档.所以我会使用更安全的方式使用复制赋值T().

  • `vector <LazyPtr <Box >>> v(100)`将使用100*sizeof(Box),这可能没问题但是OP可能不想为未分配的Box使用内存.由于OP没有描述更多要求,我们不知道...... (2认同)