返回不可变向量 unique_ptr

Return an immutable vector of unique_ptr

提问人:jozxyqk 提问时间:9/18/2023 最后编辑:jozxyqk 更新时间:9/18/2023 访问量:84

问:

我有以下对象:

class Container {
public:
    std::vector<std::unique_ptr<Item>>& items() { return m_items; }

private:
    std::vector<std::unique_ptr<Item>> m_items;
};

我想用它来使整个对象不可变,但仍然提供对 的访问,即使它在内部使用指针。例如,声明并确保代码不会意外更改其内容。constitems()void doSomething(const Container& container)

如何编写以允许对项目向量进行只读访问,而调用方无法修改任何项目、指针或向量?const auto& items() const { ... }


尝试#1:第一步是......

    const std::vector<std::unique_ptr<Item>>& items() const { return m_items; }

...

void doSomething(const Container& container)
{
    // Good: const container, can't do this
    container.items().clear();

    // Good: const unique_ptr, can't do this
    container.items()[0].reset();

    // Bad: non-const items
    *container.items()[0] = ...;
}

尝试 #2:我真正想要的是这个,但它是 UB,因为不能保证 const 类型具有相同的内存布局(也许还有其他原因?

    const std::vector<std::unique_ptr<const Item>>& items() const {
        return reinterpret_cast<const std::vector<std::unique_ptr<const Item>>&>(m_items);
        //                                                        ^_________ change unique_ptr type
    }

尝试 #3:一个相当糟糕的替代方案是构造并返回一个临时向量。同样糟糕的是缓存和维护这个重复的向量。

    std::vector<const Item*> items() const {
        return {m_items.begin(), m_items.end()};
    }

尝试 #4:实现类似 的东西,但让迭代器只返回 const 引用。在这种情况下,它需要解开 std::unique_ptr。这将起作用,但对于一个用例来说,这需要相当多的努力。也许也进入了过度工程的领域?std::span

对于期望某些类型但在迭代时不使用的代码,可能会有一些意想不到的副作用,但我对此感到满意。auto


[编辑]这与深拷贝的概念隐约相似。遵循此处的术语引线:

C++ 指针 转换 不可变性 const-pointer

评论

0赞 Sam Varshavchik 9/18/2023
为了实现所需的行为,必须返回一个自定义代理对象,该对象满足 C++ 容器的所有要求,并具有所需的语义。为了实现这一点,没有一个咒语可以说出,必须编写一大堆代码(但它是可行的)。您对 C++ 容器的技能水平和知识水平以及容器要求是什么?items
0赞 user17732522 9/18/2023
当访问返回的指针时,尝试 #2 是 UB,无论内存布局如何。
0赞 user17732522 9/18/2023
#4 对我来说听起来是正确的方法。它还会从界面中删除。如果用户不应该能够修改容器,那么容器可能也不应该是接口的一部分。返回具有所需行为的未指定范围类型应该不会太困难,例如 a 就足够了。std::vectorviews::transform
0赞 jwezorek 9/18/2023
您可以返回对 const 项的引用的范围视图

答: 暂无答案