问题描述
请考虑以下课程
class Base {
public:
virtual void do_stuff() = 0;
};
class Derived : public Base {
public
virtual void do_stuff() { std::cout << "I'm useful"; };
};
现在让我们说我想让另一个类负责拥有Base
派生类型的对象,并通过调用它们的do_stuff()
方法遍历它们.看起来像这样,但是我不知道T
应该声明为
Now let's say I want to have another class responsible for owning objects of Base
's derived types and iterate through them calling their do_stuff()
method. It looks like this, but I don't know what T
should be declared as
class Owner {
public:
void do_all_stuff() {
//iterate through all items and call do_stuff() on them
}
void add_item(T item) {
items.push_back(item);
}
vector<T> items;
}
我看到了几种可能性:
T
不能为Base
,因为我只能添加具体类型为Base
的对象,所以这是不可能的.
T
can't be Base
, since I would only be able to add objects of concrete type Base
, so that's out of the question.
T
可以是Base*
或Base&
,但是现在我需要信任add_item()
的调用者,以便向我传递指向从我从.我不能delete
的析构函数中的元素,因为我不知道它们是动态分配的.但是,如果有,应该delete
,这使我的模棱两可.
T
can be Base*
or Base&
, but now I need to trust the caller of add_item()
to pass me a pointer or a reference to an object that will still exist when I retrieve it from items
. I can't delete
the elements in Owner
's destructor, since I don't know that they were dynamically allocated. However, they should be delete
'd if they were, which leaves me with ambiguous ownership.
T
可以是Base*
或Base&
,我在Owner
中添加了Base* create_item<DerivedT>() { return new DerivedT; }
方法.这样,我知道指针将保持有效并由我拥有,但是我无法在DerivedT
上调用非默认构造函数.同样,Owner
也负责实例化对象.我也必须删除Owner
的析构函数中的每个项目,尽管这不是什么大问题.
T
can be Base*
or Base&
and I add a Base* create_item<DerivedT>() { return new DerivedT; }
method to Owner
. This way, I know the pointer will remain valid and I own it, but I'm unable to call a non-default constructor on DerivedT
. Also, Owner
becomes responsible for instantiating objects as well. I also have to delete every item in Owner
's destructor, although that's not much of an issue.
基本上,我希望能够执行以下操作:
Basically, I'd like to be able to do something similar to:
Owner owner;
void add_one() {
Derived d;
owner.add_item(d);
}
void ready() {
owner.do_all_stuff();
}
void main() {
for(int i = 0; i < 10; ++i) {
add_one();
}
ready();
}
我确定其中有一些与移动语义有关的东西(我可以移动传递给add_items()
的对象以拥有它们),但是我仍然不知道如何声明我的集合.
I'm sure there's something related to move semantics in there (I could move the objects passed to add_items()
to own them) but I still can't figure out how my collection would be declared.
这种多态所有权(尤其是STL容器)的C ++习惯用法是什么?
What is the C++ idiom for this sort of polymorphic ownership (particularly with STL containers)?
推荐答案
多态对象必须通过指针或引用来处理.由于它们的生命周期可能不受特定范围的约束,因此它们也可能具有动态存储持续时间,这意味着您应该使用智能指针.
Polymorphic objects have to be handled by pointer or reference. Since their lifetime is probably not bound to a particular scope they will also probably have dynamic storage duration, which means you should use a smart pointer.
std::shared_ptr
和std::unique_ptr
之类的智能指针在标准集合类型中可以正常工作.
Smart pointers such as std::shared_ptr
and std::unique_ptr
work just fine in the standard collection types.
std::vector<std::unique_ptr<Base>>
在Owner
中使用它的方式如下:
Using this in Owner
looks like:
class Owner {
public:
void do_all_stuff() {
//iterate through all items and call do_stuff() on them
}
void add_item(std::unique_ptr<Base> item) {
items.push_back(std::move(item));
}
vector<std::unique_ptr<Base>> items;
}
add_item
的参数类型标识添加项目所需的所有权策略,并且要求用户不遗余力地将其搞砸.例如,由于unique_ptr
具有显式构造函数,因此它们不能偶然传递具有某些隐式,不兼容的所有权语义的原始指针.
The argument type to add_item
identifies the ownership policy required for adding an item, and requires the user to go out of their way to screw it up. For example they can't accidentally pass a raw pointer with some implicit, incompatible ownership semantics because unique_ptr
has an explicit constructor.
unique_ptr
也将负责删除Owner
拥有的对象.尽管您确实需要确保Base
具有虚拟析构函数.使用当前定义,您将获得未定义的行为.多态对象应该几乎总是具有虚拟析构函数.
unique_ptr
will also take care of deleting the objects owned by Owner
. Although you do need to ensure that Base
has a virtual destructor. With your current definition you will get undefined behavior. Polymorphic objects should pretty much always have a virtual destructor.
这篇关于拥有多态对象集合的首选C ++习惯用法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!