在我的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提供了此处可能不需要的开销。

09-10 04:50
查看更多