我创建了一个容器来控制某些类型的对象的生命周期(新/删除),以避免任何编程错误。例如,删除对象时不会通知容器。对象继承自相同的基类(GreetingBase)。

对于实现,我使用“模板技巧”:

class GreetingBase{
public:
  virtual void sayHello(){
    std::cout << "Hello there!" << endl;
  }

  virtual ~GreetingBase(){}
};

class GreetingDerived: public GreetingBase{
public:
  virtual void sayHello(){
    std::cout << "Hola amigos!" << endl;
  }
  virtual ~GreetingDerived(){}
};

class GreetingContainer{
public:
   template <class T>
   void addClass(){
      items.push_back(new T());
   }
~GreetingContainer(){
   for(std::vector<GreetingBase*>::iterator it = items.begin();
   it < items.end(); it++ ){
   delete *it;
 }
}

void talk(){
  for(std::vector<GreetingBase*>::iterator it = items.begin();
    it < items.end(); it++ ){
      (*it)->sayHello();
   }
  }
private:
 std::vector<GreetingBase*> items;
};


int main(){
  GreetingContainer container;
  container.addClass<GreetingDerived>();
  container.talk();
  return 0;
}


问题:


使用模板来解决这个问题是一种常见的方法吗?有什么缺点吗?
当不是从“ GreetingBase”派生“ T”时,报告“更好的错误消息”的任何“标准方法”


先感谢您。

最佳答案

使用模板来解决这个问题是一种常见的方法吗?


我不知道这是否常见,但看起来足够明智。它确保您的容器只能包含指向用new分配的对象的指针,这很好。


  有什么缺点吗?


主要问题是您的容器破坏了Rule of Three。它具有隐式生成的复制构造函数和复制赋值运算符,它们仅复制每个指针。这将为您提供两个容器对象,它们的析构函数都试图删除相同的对象。

最简单的解决方法是删除这些成员函数,或者如果您对2011年前的语言不满意,则将其声明为私有(无实现)。如果您需要能够复制容器,则需要实现它们以安全地进行复制。

就个人而言,我将使用智能指针而不是滚动自己的RAII容器。如果容器要具有排他所有权,请使用std::unique_ptr,如果您要共享所有权,请使用std::shared_ptr,或者std::weak_ptr可以保留对由共享指针管理的对象的非所有权引用。如果您被困在过去,则unique_ptr将不可用,但是Boost提供与您类似的shared_ptrweak_ptrPointer containers


  当不是从“ GreetingBase”派生“ T”时,报告“更好的错误消息”的任何“标准方法”


在C ++ 11中,您也许可以使用静态断言,例如:

static_assert(std::is_base_of<GreetingBase, T>::value,
              "Wrong type for GreetingContainer");


另外,通过创建本地指针,您可能会得到稍微可读的错误消息。那么错误消息至少不会包含push_back的全名:

GreetingBase * p = new T();
items.push_back(p);


错误消息将类似于can't convert Whatever* to GreetingBase*,应该足够清楚。

关于c++ - 管理生命周期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12580857/

10-11 15:27