0

在我的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));

示例用法:

主文件

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));
}
4

1 回答 1

1

如果一个类是可移动的,那么它将依次移动它的成员。为了提高效率,这些成员必须是小型 POD,或者必须在堆上分配。您必须添加此功能,不要忘记移动任何成员,并且需要注意对象切片。

鉴于该类是不平凡的,当您直接使用指针时,您将拥有最有效的移动构造(当然以堆分配时间为代价)。不可能进行切片,也不会忘记移动任何成员,因为您一次性移动了整个对象。需要注意的一个障碍是跟踪谁拥有指针 - 你最好把它放在石头上,但如果这样做了,那么就没有问题了。

移动语义很棒,但是如果您的类有点涉及,我认为在这种情况下使用指针更容易/更有效。因此,我会坚持使用指针变体,并确保您的集合将拥有指针(并通过 RAII 再次释放它们) - 在您的公共界面中自由使用注释这样说。您可以通过存储某种形式的智能指针来做到这一点(提示:小心使用 unique_ptr!),或者(不太安全)制作并始终使用一个 Clear() 成员,该成员在 clear()'ing 集合之前删除所有指针。

编辑

当您将小部件成员定义为向量类型时,示例代码可以是:

类 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 会产生这里可能不需要的开销。

于 2014-02-11T08:26:38.910 回答