返回类成员无副本vs返回抽象基类的不同实现中的本地对象

时间:2018-11-05 17:57:33

标签: c++ oop

假定以下设置,其中我有一些抽象基类,它们定义了返回方法GetData的方法,例如std::vector和两个派生类,其中一个派生类的数据格式与由GetData(以下为ProperSomeClass返回),并且内部以某种奇怪的旧式C格式保存数据,即必须将该格式转换为std::vector中的GetData({ {1}})。

DerivedSomeClass

我正在寻找一种更好的方法来定义class ISomeClass { virtual std::vector<int> GetData() const = 0; }; class ProperSomeClass : public ISomeClass { private: std::vector<int> _data; public: std::vector<int> GetData() const { return _data; } }; class DerivedSomeClass : public ISomeClass { private: const void* _legacyFormat; public: std::vector<int> GetData() const { std::vector<int> temporary; // some code that extracts relevant data from legacy format return temporary; } }; (的返回值),使得GetData不必复制其ProperSomeClass成员。

我无法返回const引用,因为_data随后将返回对已删除的本地对象的引用。

返回(智能)指针时,我必须考虑DerivedSomeClass::GetData需要分配必须由调用方释放的内存,而由DerivedSomeClass::GetData返回的指针所指向的内存一定不能被调用者释放了,我不知道该如何解决(除了使用ProperSomeClass::GetData中的shared_ptr需要保留一个副本,而不再使用它只是为了不删除其数据,在我看来这很丑陋。)

简而言之,理想情况下,我“只是”想要

  • ProperSomeClass在不复制数据的情况下为我提供了const引用
  • ProperSomeClass::GetData构造向量并将其返回
  • 用于我的基类的通用API

有没有办法做到这一点?或者,这是替代/更好的方式吗?

3 个答案:

答案 0 :(得分:0)

您可以在ctor中初始化的std::vector中添加DerivedSomeClass,然后在GetData中作为const ref返回,即:

class DerivedSomeClass : public ISomeClass
{
public:
    DerivedSomeClass(void* legacyFormat):
    _legacyFormat(legacyFormat),
    _data(makeVectorFromLegacy(_legacyFormat))
    {}
private:
    const void* _legacyFormat;
    const std::vector<int> _data;
public:
    const std::vector<int>& GetData() const
    {
        return _data;
    }  
};

具有帮助函数,该函数可从const void*指针创建该矢量,该方法与在DerivedSomeClass::GetData()中提取数据的方式相同,只需要执行一次即可。

这与ProperSomeClass稍有重复,这对您可能有好处,也可能没有好处,尽管它的优点是不会在每个派生类上强制使用std::vector成员变量,从而可以将来可能不需要或不需要该成员std::vector的实现。

答案 1 :(得分:0)

ISomeClass的定义属性是使std::vector<int>可用。由于ProperSomeClassDerivedSomeClass都是从ISomeClass派生的,因此它们都必须以相同的方式使该向量可用。例如,如果您希望通过const引用(对我来说这很合理)的方式,则需要将vector用作这两个类的成员。

请考虑在std::vector<int>中拥有成员DerivedSomeClass。如果要避免两次存储相同的数据(在向量和“旧格式”指针中),则可以在构造函数中而不是DerivedSomeClass::GetData上“提取相关数据”,并摆脱{{1 }}成员。

如果_legacyFormat绝对需要保留DerivedSomeClass,我会认为此类和_legacyFormat应该分开存放。

答案 2 :(得分:0)

这里的关键是您要从接口返回一些东西,具体取决于具体的实现,而该东西需要被调用方销毁(返回副本/唯一所有权)或不被销毁(返回对成员的引用)。调用者显然在编译时不知道这一点,因此我们需要一种机制来确定销毁对象的方式。您可以这样写,以便更明确地表达自己的意图,但我认为std::shared_ptr可以达到目的:

#include <vector>
#include <memory>

using VectorPtr = std::shared_ptr<std::vector<int>>;

class ISomeClass
{
  virtual VectorPtr GetData() const = 0;
};

class ProperSomeClass : public ISomeClass
{
private:
  VectorPtr _data;
public:
  VectorPtr GetData() const { return _data;  }
};

class DerivedSomeClass : public ISomeClass
{
private:
  const void* _legacyFormat;
public:
  VectorPtr GetData() const
  {
    VectorPtr temporary;
    // some code that extracts relevant data from legacy format
    return temporary;
  }
};