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