为什么Qt的SimpleTreeModel示例使用std::vector<std::unique_ptr<>>而不是简单的std::vector<>?

问题描述 投票:0回答:1

我在一个项目中使用 Qt 6.5,并尝试重构/改进最初用 Qt 5.10 编写的树模型。我花了一些时间查看 Qt 的 SimpleTreeModel 示例,并成功使用代码创建了我自己的模型:

class TreeItem
{
public:
    explicit TreeItem(QVariantList data, TreeItem *parentItem = nullptr);

    void appendChild(std::unique_ptr<TreeItem> &&child);

    TreeItem *child(int row);
    int childCount() const;
    int columnCount() const;
    QVariant data(int column) const;
    int row() const;
    TreeItem *parentItem();

private:
    std::vector<std::unique_ptr<TreeItem>> m_childItems;
    QVariantList m_itemData;
    TreeItem *m_parentItem;
};

但让我烦恼的是

std::vector<std::unique_ptr<TreeItem>>
的使用(在之前的 Qt 版本中为
std::vector<TreeItem*>
)。为什么使用它而不是使用更简单的
std::vector<TreeItem>

我认为在这里使用指针没有任何意义,无论是基本的还是智能的,因为这增加了不必要的间接级别,并且对于具有大量项目的模型来说可能成本高昂。

c++ qt vector std
1个回答
0
投票

动态容器中的项目可能会移动。在这个数据结构设计中,每个

TreeItem
都需要知道它的父级。如果
m_childItems
包含实际的
TreeItem
对象,则当向量调整大小时它们将移动到不同的地址。那时,孩子的父指针将成为悬空指针。需要一些更复杂/昂贵的方法来跟踪父项。

因此,每个

TreeItem
一旦创建就需要保留在固定的内存位置。简单的解决方案是,如果
m_childItems
包含指向从堆分配的项目的指针。

手动内存管理是现代 C++ 代码中的一大禁忌,这是有充分理由的,因为这是 C 和遗留 C++ 代码中错误的巨大来源。

std::unique_ptr
是 C++ 类,用于存储指向具有单一所有者且没有共享所有权的对象的指针。当
m_childItems
被破坏时,现在也会自动破坏其中的所有 TreeItem。这就是向量不包含原始指针的原因。

另一点是,

TreeItem
具有不小的复制/移动成本,因此如果
m_childItems
包含实际对象而不是指针,那么调整大小的向量会稍微昂贵。仅复制/移动指针要快得多。

所以这就是为什么

m_childItems
包含指针,以及为什么在这种情况下指针是
std::unique_ptr
。不同的用例或设计可能会使用/需要
std::shared_ptr
std::weak_ptr
,但如果不需要,拥有
std::unique_ptr
和原始非拥有指针会更简单、更好。

© www.soinside.com 2019 - 2024. All rights reserved.