【问题标题】:How could I store a class without copy constructor in std::vector?如何在 std::vector 中存储没有复制构造函数的类?
【发布时间】:2018-11-24 03:04:45
【问题描述】:

在我们的项目代码中,不应复制资源类型。

struct Res {
    ....
    Res(const Res& rhs) = delete;
    Res& operator=(const Res&) = delete;
    Res(Res&&) = delete;
    Res& operator=(Res&&) = delete;
};

但是,std 容器似乎都需要复制构造函数。那么如何将 Res 存储在 std::vector 中?

class ResourceCache{
    ....
    const Res& GetRes(size_t index);
    std::vector<Res> resources_;
}

【问题讨论】:

  • 你刚刚回答了你自己的问题:你不能。但是,例如,您可以在向量中存储 std::shared_ptrstd::unique_ptr。如果您的类的所有实例都是在动态范围内创建的,那么您一定已经在使用智能指针,对吧?如果是这样,也只需将它们存储在向量中。问题解决了。
  • 物体可以移动吗?
  • 正如问题中明确显示的那样,对象也不能移动,所以这不是该问题的欺骗,但是,无论如何......
  • emplace_back 会直接在容器中构造对象。
  • @MichaelSurette:这将需要 vectorreserve 空间一次,但永远不会再次调整大小;否则,容量变化将迫使将元素从旧存储移动到新存储,这将失败。 C++11 及更高版本在理论上通常允许 vectors 使用它,但提到大多数方法都有更严格的要求。

标签: c++ copy-constructor


【解决方案1】:

由于您已经删除了复制和移动构造函数/赋值运算符,答案是:您不能以任何合理的方式使用这样的vector。如果没有复制或移动选项,您最多只能将reserve 空格 onceemplace_back 预置到 vector 中,但任何可能随后更改容量的内容,或以任何方式重新排列元素都是非法的(因为它会隐含地涉及使用移动或复制操作)。

尽管在 cmets 中提到,您可以创建一个智能指针 vector,其中只有智能指针必须移动/复制,而不是它指向的 Res 实例,并获得一个功能齐全的 vector .例如,使用std::unique_ptr,您的类可以实现为:

class ResourceCache{
    ....
    const Res& GetRes(size_t index) {
        return *resources_.at(index);  // Can still provide const references at API level
    }
    std::vector<std::unique_ptr<Res>> resources_;
}

您只需使用resources_.push_back(std::make_unique&lt;Res&gt;(...args to Res constructor...)) 来创建/插入元素到resources_,而不是resources_.push_back(Res(...args to Res constructor...))

【讨论】:

  • 对于大约 100,000 个对象和GetRes 的频繁调用,我猜解引用指针会花费很多。如果没有复制构造函数,std::array 会正常工作吗?或者我应该用新的位置分配一个大块内存?
  • @heLomaN:别猜了;轮廓。我怀疑你会发现你的猜测是错误的。 GetRes 返回一个引用,在大多数情况下,它的功能就像一个指针(在我知道的所有编译器上),所以 return *resources_.at(index); 在您返回时实际上不会尊重指针,只需将其转换为引用。虽然您的 Res 对象在内存中不会是连续的(这可能增加缓存未命中),否则行为将是相同的,间接查找的数量与以前相同。我强烈建议在假设它太慢之前尝试使用std::unique_ptr
  • @heLomaN:如果这确实成为一个问题,std::vector 与初始 reserve 后跟 emplace_back 可能有效(std::array 不合适,因为它仅通过聚合初始化进行初始化,这使动态填充成为问题)。但如果做不到这一点,你可能会被::operator new 卡住来获取内存块,然后放置新的来填充它。
  • emplace_back() 将不起作用。即使有预先保留的空间,emplace_back() 仍会生成代码来重新分配向量。某个翻译单元中的随机emplace_back() 不知道它总是有可用的保留空间,因此需要为这种可能性生成重新分配代码,这将在此处失败,因为无法复制/移动类。自己试试。它不会起作用。
  • @SamVarshavchik:谢谢。我认为这是一种可能性(因此符合“可能”)。使用指定的 STL 猜测 OP 的目标实际上是不可能的。
猜你喜欢
  • 2020-10-05
  • 2012-11-03
  • 2023-03-31
  • 2018-03-12
  • 2012-06-01
  • 2012-07-10
  • 1970-01-01
  • 2020-08-06
  • 2020-08-13
相关资源
最近更新 更多