【问题标题】:C++ read-only struct that can be set from within a class?可以从类中设置的 C++ 只读结构?
【发布时间】:2018-06-27 17:28:30
【问题描述】:

我有一个类Foo,它在其中定义了一个公共结构Data,其中一个QVector<Data> allData 嵌套了Data 结构的多个对象:

class Foo
{
    public:
        struct Data {
            uchar valueA;
            uchar valueB;
            uchar valueC;
        };
    private:
        QVector<Data> allData;
};

我还有另外两个 B 类和 C 类需要每秒读取多次 allData。他们根本不能写入allData,这只能由Foo类处理。

考虑到性能,我正在寻找一种方法来做到这一点,而无需每次都创建新的 QVector。据我了解,这样的方法:

QVector<Data> getAllData() {
    return allData;
}

将导致每次调用此方法时都会创建一个新对象。

如果我给其他类提供了类似 QVector&lt;Data&gt; allDataCopy 的东西,它刚刚被移交给 Foo 以填充 allData 中的值,这只会导致每次都必须复制所有值,我想象也不会很好。

有没有什么有效的方法来解决这个问题?

【问题讨论】:

  • QVectorcheap to copy。也就是说,你可以做到const QVector&lt;Data&gt;&amp; getAllData()
  • 您可以通过 const 引用返回,因为该值是成员变量,但我不确定这是否安全。
  • “每秒多次”:请给出我们所说的“多次”的顺序。单位?十?数百?百万?
  • 为什么使用 QVector 而不是 std::vector?
  • @manni66:我在想这可能是一个问题本身的基础。结果是there is one

标签: c++ performance struct qvector


【解决方案1】:

除非您想强制用户复制,否则您的“getter”不应按值返回。提供两个重载,分别返回一个左值引用和一个const左值引用(或者如果你不希望Foo的用户只返回一个const变异allData):

QVector<Data>& getAllData() {
    return allData;
}

const QVector<Data>& getAllData() const {
    return allData;
}

这仍将允许您的用户制作副本(如果需要),但也允许您的用户通过引用仅观察/变异allData,而无需任何副本。


在 C++11 及更高版本中,如果 QVector 支持移动语义,您可能还希望重载 &amp;&amp; ref 限定符:

QVector<Data>& getAllData()       &      { return allData; }
const QVector<Data>& getAllData() const& { return allData; }
QVector<Data> getAllData()        &&     { return std::move(allData); }

这允许用户方便地从Foo 类型的右值移动allData

【讨论】:

  • 一般来说是个好建议。虽然我想补充一点,QVector 是隐式共享的。复制构造函数始终是常数时间,相反,当任何引用写入共享实例时,元素都会被复制。
  • QVector has a move constructor since Qt 5.2。但是拥有一个移动成员变量的 getter 似乎是一个糟糕的主意。我错了吗?
  • @FredLarson 请注意,特定的 getter 是使用 &amp;&amp; 限定的引用,这意味着它仅在您从右值调用它时才参与。例如std::move(foo).getAllData() 会搬出allDatafoo.getAllData() 不会。
  • @FrançoisAndrieux:谢谢。我还不习惯那些限定词。
  • OP 不想要第一个重载,第二个就足够了。
【解决方案2】:

QVector 复制成本低;它在写语义上使用智能引用副本。

如果您的代码有任何多线程访问的危险,QVector const&amp; 是危险的,因为引用不是线程安全的。如果您是可重入的,也会发生同样的危险,并导致在其他人持有 QVector const&amp; 的同时修改 QVector

只需返回QVector 的副本。涉及引用的花哨替代方案可能会导致潜在的错误,在您有证据表明“复制”QVector 的小成本导致性能问题之前,请不要考虑它们。

【讨论】:

    猜你喜欢
    • 2012-12-15
    • 2012-11-22
    • 2019-01-21
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多