首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >管理生命周期

管理生命周期
EN

Stack Overflow用户
提问于 2012-09-25 10:16:54
回答 3查看 102关注 0票数 0

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

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

代码语言:javascript
复制
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;
}

问题:

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

提前谢谢你。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-25 10:28:10

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

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

有什么缺点吗?

主要问题是您的容器破坏了三条规则。它有一个隐式生成的复制构造函数和复制赋值操作符,它简单地复制每个指针;这将给出两个容器对象,它们的析构函数都试图删除相同的对象。

解决这个问题的最简单的方法是删除这些成员函数,或者声明它们是私有的(没有实现),如果您被困在2011年之前的语言版本中。如果您需要能够复制容器,那么您需要实现它们才能安全地完成。

就我个人而言,我会使用智能指针,而不是滚动自己的RAII容器;如果容器具有独占所有权,则使用std::unique_ptr;如果希望共享所有权,则使用std::shared_ptr,或者使用std::weak_ptr来保存对由共享指针管理的其他地方管理的对象的非所有者引用。如果您停留在过去,那么unique_ptr将不可用,但是Boost提供了与您类似的shared_ptrweak_ptr指针容器

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

在C++11中,您可以使用静态断言,如下所示:

代码语言:javascript
复制
static_assert(std::is_base_of<GreetingBase, T>::value, 
              "Wrong type for GreetingContainer");

或者,通过创建一个本地指针,您可以得到一条可读性稍高的错误消息;然后,错误消息至少不会包含push_back的全名。

代码语言:javascript
复制
GreetingBase * p = new T();
items.push_back(p);

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

票数 2
EN

Stack Overflow用户

发布于 2012-09-25 10:20:37

  1. 为此使用template是可以的,但是使用函数接收pointer to base-class更好。
  2. 标准的C++11方式-使用static_assert。没有C++11 - boost等价物,或者你自己的元函数。

附带注意:如果使用smart pointers,则不需要编写此类容器。

票数 1
EN

Stack Overflow用户

发布于 2012-09-25 10:24:45

我认为让addClass成为一个模板没有什么好处;它只是意味着您得到了针对每种不同类型实例化的代码的新副本,并且强制执行了特定的构造函数调用。

只需使它成为一个简单的函数,接受一个基类指针:

代码语言:javascript
复制
void addClass(GreetingBase *o){
    items.push_back(o);
}

所以你的来电者

代码语言:javascript
复制
container.addClass( new GreetingDerived() );

而不是

代码语言:javascript
复制
container.addClass<GreetingDerived>();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12580857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档