【问题标题】:vector::push_back <MyClass> not work for non default constructorvector::push_back <MyClass> 不适用于非默认构造函数
【发布时间】:2012-10-18 10:48:23
【问题描述】:

我有一个Controls 类,它具有默认构造函数和复制构造函数以及其他构造函数,以及一个赋值运算符,我想使用向量创建我的类的数组。当我调整矢量大小时,我会正确初始化对象;但是当我想使用非默认构造函数创建我的对象时,我得到了这个错误,

调用纯虚方法 在没有活动异常的情况下终止调用

Controls.h

class Controls : public QObject
{

private:

    QHBoxLayout Layout ;
    string Controlname;
    std::auto_ptr<QLabel> Label ;
    std::auto_ptr<QSlider> Slider ;
    std::auto_ptr<QSpinBox> Spin ;

public:

    Controls(QLayout &Parent , string name , const int &Default_value);
    Controls(const Controls &copy);
    Controls();
    ~Controls();

    QLabel *const Get_Label()const { return Label.get() ; }
    QSlider *const Get_Slider()const { return Slider.get() ; }
    QSpinBox *const Get_Spin()const { return Spin.get() ; }
    QHBoxLayout *const Get_Layout() {return &Layout;}

    void SetValue(const int &newvalue);

    Controls &operator= (const Controls &copy);


};

Controls.cpp

Controls &Controls::operator= (const Controls &copy)
{
    Label = std::auto_ptr<QLabel> ( new QLabel() ) ;
    Slider = std::auto_ptr<QSlider> ( new QSlider() ) ;
    Spin = std::auto_ptr<QSpinBox> ( new QSpinBox() ) ;

    Slider->setValue(copy.Get_Slider()->value());
    Slider->setOrientation(Qt::Horizontal);
    Label->setText(QString ("unamed"));
    Spin->setValue(copy.Get_Spin()->value());


    Layout.addWidget(Label.get() , 0 , 0);
    Layout.addWidget(Slider.get() , 0 , 0);
    Layout.addWidget(Spin.get() , 0 , 0);

    QObject::connect(Slider.get() , SIGNAL(valueChanged(int) ) , Spin.get() , SLOT(setValue(int)));
    QObject::connect(Spin.get() , SIGNAL(valueChanged(int) ) , Slider.get() , SLOT(setValue(int)));


    return *this ;
}
Controls::Controls(const Controls &copy)
{
    *this = copy ;
}
Controls::Controls()
{

    Label = std::auto_ptr<QLabel> ( new QLabel() ) ;
    Slider = std::auto_ptr<QSlider> ( new QSlider() ) ;
    Spin = std::auto_ptr<QSpinBox> ( new QSpinBox() ) ;

    Slider->setValue(0);
    Slider->setOrientation(Qt::Horizontal);
    Label->setText(QString ("unamed"));
    Spin->setValue(0);


    Layout.addWidget(Label.get() , 0 , 0);
    Layout.addWidget(Slider.get() , 0 , 0);
    Layout.addWidget(Spin.get() , 0 , 0);

    QObject::connect(Slider.get() , SIGNAL(valueChanged(int) ) , Spin.get() , SLOT(setValue(int)));
    QObject::connect(Spin.get() , SIGNAL(valueChanged(int) ) , Slider.get() , SLOT(setValue(int)));
}
Controls::Controls(QLayout &Parent , string name , const int &Default_value)
{
    Controlname = name ;

    Label = std::auto_ptr<QLabel> ( new QLabel() ) ;
    Slider = std::auto_ptr<QSlider> ( new QSlider() ) ;
    Spin = std::auto_ptr<QSpinBox> ( new QSpinBox() ) ;

    Slider->setValue(Default_value);
    Slider->setOrientation(Qt::Horizontal);
    Label->setText(QString (name.c_str()));
    Spin->setValue(Default_value);


    Layout.addWidget(Label.get() , 0 , 0);
    Layout.addWidget(Slider.get() , 0 , 0);
    Layout.addWidget(Spin.get() , 0 , 0);

    QObject::connect(Slider.get() , SIGNAL(valueChanged(int) ) , Spin.get() , SLOT(setValue(int)));
    QObject::connect(Spin.get() , SIGNAL(valueChanged(int) ) , Slider.get() , SLOT(setValue(int)));

    Parent.addItem(&Layout);

}

void Controls::SetValue(const int &newvalue)
{
    Slider.get()->setValue(newvalue);
}
Controls::~Controls()
{

}

main.cpp …… .

   vector <Controls> i ;
      i.resize(2 ); // this is work 

     i.push_back(Controls(layout , "WHITE_BALANCE_RED_V" ,12);// this is not working 

【问题讨论】:

  • 我猜这只是编辑问题,但这行已经很糟糕了,应该是 "i.push_back(Controls(layout , "WHITE_BALANCE_RED_V" ,12));"
  • 对不起!我忘记了逗号(我现在编辑它),但我在我的真实代码中使用它!我得到输出:当我使用 push_back 时,调用终止的纯虚拟方法没有活动异常

标签: c++ qt


【解决方案1】:

这与std::vector 和非默认构造函数无关。 您没有提供完整的代码,但我认为这是previous question 的延续。

您的Controls::operator= 无效,它会创建QWidgets 的副本,并将它们放入全新的QLayoutControls 传递给 push_back 的对象是临时对象,在调用后被销毁,它的副本被放入向量中。但是被破坏的对象的QWidget 成员被放入QLayout,它不会被破坏并被添加到您尝试显示的小部件(Panel)中。临时 Controls 对象被销毁后,Panel-&gt;show() 调用 Panel 的 QLayout 方法,尝试访问已删除的小部件。

您真的需要将您的Controls 对象的副本 保存在您的向量中吗?如果您存储指针,那将解决您的问题。为什么你需要那个向量?

再一次,不要使用auto_ptr,它已被弃用,您不需要它来正确管理删除QObjects

【讨论】:

  • 您的 Controls::operator= 无效;你能解释一下女巫部分是无效的吗
  • 我已经描述过 - 在operator= 中,您为目标Controls 对象创建一个新布局,并将您的小部件副本放在那里。当源Controls 对象(您从中复制)被销毁时,小部件也会被删除(感谢auto_ptr),但指向它们的指针存储在您之前在堆栈上创建的QVBoxLayout layout 对象中。然后将layout 设置为Panel。当您调用Panel-&gt;show() 时,它会为layout 对象调用QLayout 的方法,而后者又会尝试调用已删除小部件的方法。
  • 请描述一下,为什么需要在这个向量中存储Controls 对象的副本?你能存储指针吗?您需要存储它们吗?
  • 我不想存储 Controls 的副本,我想存储新的 Controls 对象。
  • 然后考虑存储指针(但不是 auto_ptrs,您可以存储原始指针或 shared_ptrs 或 QSharedPtrs,无论您喜欢什么)。 std::vector::resize 之所以有效,是因为它要么不复制任何东西(有足够的内存来扩展向量存储),要么因为它复制了默认构造的 Controls 对象,这些对象在任何地方都没有使用。
【解决方案2】:

另外,我认为问题出在您的 auto_ptr 变量上。您应该检查它是否真的是您想要处理对象指针的方式。我宁愿坚持使用 shared_ptr 或 unique_ptr。然而,在后一种情况下,您根本不想拥有复制构​​造函数,因为指针可能只有一个所有者。

C++ std::auto_ptr copy constructor

【讨论】:

    【解决方案3】:

    我不确定您是否正确实现了复制语义,并且将 std::auto_ptr 用作数据成员是一种“警告标志”。

    你的Controls真的可以深度复制吗?

    也许你应该只使用 scoped_ptr 而不是 auto_ptr 数据成员,禁止复制声明 private 复制构造函数和 private operator=,并使用 vector&lt;shared_ptr&lt;Controls&gt;&gt; ?

    (或者使用C++11和移动语义,所以使用unique_ptr而不是auto_ptr,只使用编译器自动生成的移动操作?)

    【讨论】:

      【解决方案4】:

      当使用auto_ptr 时,您应该使用release 而不是get 将指针传递给新所有者:

      Controls::Controls(QLayout &amp;Parent , string name , const int &amp;Default_value) 中没有这个:

      Layout.addWidget(Label.get() , 0 , 0);
      

      但是:

      Layout.addWidget(Label.release() , 0 , 0);
      

      否则 - 您的 auto_ptr 将删除此构造函数范围末尾的指针。

      【讨论】:

        猜你喜欢
        • 2013-05-06
        • 1970-01-01
        • 2012-07-30
        • 2018-04-19
        • 2010-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多