你如何在 C++ 中 return 一个接受纯虚拟(const ref)参数的对象?

How do you return an object that takes pure virtual (const ref) arguments in C++?

我有一个包含抽象 class 实例列表的对象。

class A { };  // abstract class

class B {
 public:
  void addA(const A& a) {
    list_of_a_.push_back(&a);
  }
 private:
  std::vector<const A*> list_of_a_;
};

A 是抽象的,所以我将它们作为指针存储在向量中,并将其作为常量引用传递。我有不同的 A.classes

然后我有一个类似工厂的函数来创建 B 和 returns 它。

B CreateB() {
  B b;
  DerivationOfA a;  // subclass of abstract class A.
  b.addA(a);
  return b;
}

int main() {
  B b = CreateB();
  b.DoSomethingWithA();  // bad memory, 'a' was destroyed.
}

问题是一旦 B 从 "create" 函数返回,A 的实例就会在堆栈上被销毁。当我使用智能指针时也会发生同样的事情。我想避免使用常规指针来避免额外的内存管理问题。

这样做有什么技巧可以保留 CreateB 函数,避免使用指针,但仍然能够将抽象 classes 传递给 B?我可以使用按值传递,只是 C++ 不允许使用抽象 classes.

编辑:我知道为什么会这样,但我不确定在使用纯虚拟对象时如何绕过它。除了我想避免的使用 C 指针之外,我不确定如何避免范围问题。

编辑2:纯虚拟classes而不是objects更准确。

编辑 3: 抽象 classes 而不是 纯虚拟 class满足挑剔。

CreateB 函数在堆栈上创建一个对象 b,当我们从该函数 return 时,堆栈被展开并且 b 超出范围。

您可以在 main 函数中创建对象 b,然后对该对象调用 addA 函数。

编辑

在堆上创建 b 并 return 引用它。

B* CreateB() {
    B *b = new B;
    // rest of the code
    return b;
}

您的设计令人困惑。通过引用接收对象并保存它的指针是个坏主意。

  • 使用智能指针。
  • 如果你想通过指针保留对象,你需要在堆上分配它(通过 new 运算符)并在你的容器中释放(通过 delete 运算符)(class with矢量成员)。
  • 如果你想通过引用传递它,你需要保证对象不会被删除。或者您需要在该函数调用期间复制该对象。

在一些库中,容器接收刚刚创建的对象指针并将其保存在内部数据中并负责删除。如果您不使用智能指针,则需要定义并记住哪个对象是指针引用的对象的主人。用指针管理对象不是简单的问题。智能指针让这更简单。

为 B 定义移动构造函数。

B factory() {
  B x;
  // some code

  return std::move(x);
  // return x; if with copy elision
}

应该可以。

如果移动语义不是一个选项。

struct B {
 public:
  class Holder {
   public:
    static Holder NewHolder() {
      return Holder(new B{});
    }
    B *ptr_;

   private:
    Holder(B *ptr) : ptr_(ptr) {}
  };

  B() : resource_(new int) {
    std::cout << "Construct" << std::endl;
  }

  B(Holder x) {
    resource_ = x.ptr_->resource_;
    x.ptr_->resource_ = nullptr;
    delete x.ptr_;
  }

  ~B() {
    std::cout << resource_ << " deleted by " << this << std::endl;
    delete resource_;
  }

  int *resource_;
};

B::Holder factory() {
  B::Holder holder = B::Holder::NewHolder();
  B &b = *holder.ptr_;
  // some code

  return holder;
}

int main() {
  B b = factory();

  return 0;
}

Holder 是一个嵌套的 class,它持有一个由 new 分配的 B。并且这个B不会被销毁,直到构造函数B(Holder x)从持有者那里窃取资源,然后构造函数删除空B。