在我的class
实现中,我有这样的东西:
基类
class swcWidget :
public swcRectangle
{
public:
swcWidget();
virtual ~swcWidget();
void update(float dt);
protected:
inline virtual void oPaintOnTop() { }
private:
};
派生类
class swcButton :
public swcWidget
,public swcText
{
public:
swcButton();
virtual ~swcButton();
static const int DEFAULT_SIZE = 20;
protected:
private:
void oPaintOnTop();
};
class swcApplication
{
public:
swcApplication(int argc, char *argv[]);
virtual ~swcApplication();
int run();
struct Controls
{
typedef std::vector<swcWidget*> vWidgets; //option 1
~Controls();
/////////////////////////////////
// M A I N P R O B L E M //
/////////////////////////////////
void add(swcWidget &&widgets); //most preferred option
//but gets demoted to base class.
void add(swcWidget *widgets); //second choice
//but should I make a copy of it?
//or just make a reference to it?
//and this one does what I wanted to.
//but still unsure on other things I don't know
void add(swcWidget *&&widgets); //this compiles fine (?)
//I don't know what kind of disaster I can make into this, but still does not do what I wanted.
inline vWidgets &getWidgets() {
return widgets;
}
private:
vWidgets widgets;
};
Controls controls;
};
我知道这样的一些工作选择:
使
swcApplication::Controls::widgets
作为类型
std::vector<std::shared_ptr<swcWidget>>
但是我的代码将绑定到
std::shared_ptr
中,并且我无法使用如下简单语法:swcButton btn;
app.controls.add(std::move(btn));
用法示例:
main.cpp
int main(int argc, char *argv[])
{
swcApplication app(argc, argv);
app.windows.create(640, 480);
if (font->load("fonts\\georgia.fnt") != BMfont_Status::BMF_NO_ERROR)
{
puts("failed to load \"georgia.fnt\"");
}
{
swcButton btn;
btn.setPosition(100, 100);
btn.setFont(font);
btn.text = "Ey!";
app.controls.add(std::move(&btn));
// btn.text = "Oy!";
}
return app.run();
}
更新:
这是
swcApplication::Controls::add()
的临时定义,尽管可能仍然有所不同void swcApplication::Controls::add(swcWidget &&widget)
{
widgets.push_back(std::move(widget));
}
最佳答案
如果一个类是可移动的,那么它将依次移动其成员。为使此方法有效,这些成员必须是小型POD或必须在堆上分配。您必须添加此功能,不要忘记移动任何成员,并且要注意对象切片。
鉴于该类并非无关紧要的,当您直接使用指针时(您当然会以堆分配时间为代价),您将拥有最有效的移动构造。由于您可以一次性移动整个对象,因此无法进行切片,也不能忘记移动任何成员。要提防的一个障碍是跟踪谁拥有这些指针-您最好将它固定在石头上,但是如果完成了,那么就不再有问题了。
移动语义很棒,但是如果您的类有些涉及,我想在这种情况下使用指针会更容易/更有效。因此,我会坚持使用指针变量,并确保您的集合将拥有该指针(并通过RAII再次释放它们)-在您的公共界面中大量使用注释。您可以通过存储某种形式的智能指针(提示:谨慎使用unique_ptr!)或(不太安全)make并始终使用Clear()成员来删除该集合,然后再使用clear()成员在清除collection()之前删除所有指针。
编辑
如果您将小部件成员定义为vector类型,则示例代码可能是:
要对swcApplication进行分类,请添加:
void swcApplication::Controls::ClearWidgets() {
for (auto& nextWidget: widgets) {
delete nextWidget;
}
widgets.clear();
}
不要忘记在适当的时间调用ClearWidgets(例如在析构函数中)。
可以通过以下方式添加小部件:
// Note: any passed widget will not be owned by you anymore!
template <typename Widget>
void swcApplication::Controls::add(Widget*& widget) {
widgets.push_back(widget);
widget = nullptr;
}
从现在开始,您可以添加小部件,例如
swcButton* btn = new swcButton;
app.controls.add(btn);
// btn is now owned by app.controls, and should be set
// to nullptr for you to prevent misuse like deleting it
尽管存储unique_ptr使得访问它们有点容易出错(在访问它们时要当心从容器中获取所有权),但在此处使用智能指针应该使其更加安全,并且shared_ptr提供了此处可能不需要的开销。