【问题标题】:Best way to return a vector member variable to external class将向量成员变量返回到外部类的最佳方法
【发布时间】:2014-12-18 19:57:36
【问题描述】:

我正在尝试用 C++ 编写 LED 灯条驱动程序。现在我有一个Strip 类和一个Driver 类; Strip 类抽象出具有多个像素的 LED 灯条,而 Driver 类将 Strip 数据聚合到单个缓冲区中以通过 UDP 连接发送。

相关的部分类:

class Strip {
  public:
    ...
    ??? getPixelData();
    int getPixelDataLength();
  protected:
    std::vector<unsigned char> mPixelData;

class Driver {
  public:
    ...
    void aggregateStrips();
  protected:
    vector<unsigned char> mBuffer;

serialize 将所有红-绿-蓝像素数据写入vector&lt;unsigned char&gt;。然后驱动程序调用Strip.getPixelData() 获取mPixelData 的地址,并调用getPixelDataLength() 计算memcpy() 的字节数。

aggregateStrips() 做了这样的事情:

int packetLength = 0;
for(auto strip : Strips) {
    memcpy(&mBuffer[packetLength], strip->getPixelData(), strip->getPixelDataLength());
    packetLength += strip.getPixelDataLength();
}

我的问题是——getPixelData() 应该返回什么?它是否应该将智能指针 (shared_ptr?) 返回到向量?或者也许是一个参考?我只想要地址(和长度),因为我打算memcpy它。

谢谢!

【问题讨论】:

    标签: c++ vector reference smart-pointers


    【解决方案1】:

    通常,您会返回对向量 (std::vector&lt;unsigned char&gt; const &amp;) 的 const 引用,在这种情况下,您还应该将方法设为 const,因为它不会修改对象:

    std::vector<unsigned char> const & getPixelData() const;
    

    调用者可以决定是否需要制作副本。

    // Causes copy-initialization.
    std::vector<unsigned char> copy = a_strip.getPixelData();
    
    // Binds a new reference to the existing vector; no copy is made.
    std::vector<unsigned char> const & not_a_copy = a_strip.getPixelData();
    

    getPixelDataLength() 也可能成为该类的 const 成员。尝试将不更改对象的任何成员设为 const 成员,因为这将允许在 Strip 为 const 的对象上调用它们。

    【讨论】:

    • 要实现getPixelData(),我只需要return mBuffer吗?还是return &amp;mBuffer?
    • @nathanlachenmyer return mBuffer;&amp; 将获取地址,仅当您需要指针时才需要该地址。 (引用不是指针。)
    • 如果您想在 memcpy 中使用返回值(将 c 样式复制与 C++ 对象混合使用是个坏主意),那么您将不得不这样做。 const char* getPixelData(void) { return mPixelData.data();不过我更喜欢 cdhowie 关于界面外观的建议。
    • @rakeshdn 你根本不需要那个接口,你可以简单地在调用点做foo.getPixelData().data()来获得这样一个指针。
    • +1 提倡const 的正确性。更多关于这个的讨论可以在C++ Core Guidelines找到。
    【解决方案2】:

    std::vector 通过其data() 方法公开它管理的缓冲区,在这种情况下,该方法将返回unsigned char*const unsigned char *,具体取决于Strip/mBuffer 是否为const。这个方法是在 C++11 中添加的。

    附带说明一下,将只读方法设置为 const(在带括号的方法参数之后)是一个很好的设计,这样它们就可以在其类的 const 实例上调用,并且不允许修改任何成员变量。

    我会将getPixelData() 定义为:

    const unsigned char* getPixelData() const
    {
      return mBuffer.data();
    }
    

    同样,我会把getPixelDataLength()写成:

    std::size_t getPixelDataLength() const
    {
      return mBuffer.size();
    }
    

    另一方面,for(auto strip : Strips) 实际上复制了每个片段。如果您引用每个现有条带而不复制它,您的程序会更有效率:

    for (const auto& strip : Strips) {
      // ...
    }
    

    【讨论】:

    • 谢谢!我实际上并不知道我可以将引用与 auto 一起使用——这真的很聪明。我也非常感谢您引导我了解您将如何处理此问题。
    • 没问题。实际上,C++ 标准委员会目前正在考虑通过允许 for (strip : strips) 之类的内容来使 for 循环更加简单,甚至不必指定 auto&amp;
    【解决方案3】:

    我不会返回向量,而是将一对 (const) 迭代器返回到向量的开头和结尾:

    using PixelIterator = std::vector<unsigned char>::const_iterator;
    class Strip {
     ... 
     PixelIterator begin() const {
       return mPixelData.begin();
     }
     PixelIterator end() const {
       return mPixelData.end();
     }
    };
    

    如果可以的话,我会避免在 c++ 中使用memcopy。使用迭代器,您可以轻松地附加到缓冲区向量:

    for(const auto& strip : strips)
      mBuffer.insert(mBuffer.end(). strip.begin(),  strip.end());
    

    正如已经指出的,在基于范围的循环中使用auto&amp; 以避免复制。

    您不需要维护单独的长度变量,因为您可以轻松获得std::vector 的大小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-20
      • 2021-10-20
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2013-08-11
      • 2020-05-25
      相关资源
      最近更新 更多