std::vector of object containing auto_ptr behaves

2019-09-21 03:47发布

问题:

I want to create a control panel for my application using Qt library and for this i create class Controls class

Controls : create a slider and spin and a label and orgnize them in horizontal layout .

but when i want to create std::vector<Controls> the program run without error but now controls is creating at all ! so why there is no controls.

Controls.h

class Controls 
{

private:

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

public:
    Controls();
    Controls(QLayout &Parent , string name , const int &Default_value);
    Controls(const Controls &copy);
    ~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() ) ;

    this->Controlname = copy.Controlname ;
    this->Slider.get()->setValue( copy.Slider.get()->value() );
    this->Spin.get()->setValue( copy.Spin.get()->value() );

    return *this ;
}
Controls::Controls(const Controls &copy)
{
    this->Controlname = copy.Controlname ;
    this->Slider.get()->setValue( copy.Slider.get()->value() );
    this->Spin.get()->setValue( copy.Spin.get()->value() );

}
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*100);
    Slider->setOrientation(Qt::Horizontal);
    Label->setText(QString (name.c_str()));
    Spin->setValue(Default_value*100);


    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

int main(int argc, char *argv[])
{


    QApplication app (argc , argv );


    QVBoxLayout layout ;
    auto_ptr<QWidget> Panel = auto_ptr<QWidget> (new QWidget()) ;

    vector<Controls> g ;
    g.push_back(Controls(layout , "WHITE_BALANCE_RED_V" , 56 ));

        Panel.get()->setLayout(&layout);
    Panel.get()->show();

        return app.exec();

}

EDIT:

i remove auto_ptr destructor from ~controls , and when i run it again i get this exception

pure virtual method called
terminate called without an active exception
  • i initialized sliders and spin in copy constructor

回答1:

There are two "werid" things here, all related to auto_ptr.

The first is that members destructors are called automatically just past the exit of the embedder destructor. So explicitly destroy meber variables leads to "double destruction", something the compiler is not designed to manage.

(Note: the fact that a variable is called "pointer" will not make it to be anymore a variable: if using raw pointers, and calling delete pointer does not destroy the pointe-r, but the pointe-d, something that auto_ptr do by itself).

The second is that auto_ptr isn't copyable: in fact it uses copy operators to implement move semantics but... containers (like std::vector) assumes that copy is ... copy (not move).

In the most of std::vector (and std::list, as well) implementations this is not an issue because the implemetors payed attention to that point and avoid their containers to generate simultaneously existent copies. But some mutational algorithms cannot work consistently, simply because they inadvertently "move" to the wrong place - the one that will be destroyed just after the function return ... sigh!)

This second aspect is solved by C++11, by implementing containers supporting both copyable and movable elements (being C++11 equipped with r-value references, copy and move are well distinguished operations) and deprecating auto_ptr in favor of unique_ptr, that, implement "move" not "above copy" but "instead of copy".

Moral of the story: In C++11 use unique_ptr instead of auto_ptr.

In C++03, don't use auto_ptr in containers or in object that have to stay into containers.

Use raw pointer and define a proper (for your object) copy semantics (by doing a "deep copy" making copy of pointers to point to copy of objects) or sharing semantics (by making pointer to point to a same objects, and manage reference counting to trigger destruction of the pointed elements. boost::shared_ptr is an example of such a "pointer")



回答2:

the program run without error but now controls is creating at all !

That is actually very strange, because in Controls::Controls(const Controls &copy) you are calling this->Slider.get() which will return 0, because your members are not yet initialized.

Firstly, you need to read and understand how to use auto_ptr.

Secondly, you should forget about auto_ptr and never use it further. Qt has its own smart pointers, but they are not needed in your case because QObjects manage lifetime of their children.

So, thirdly, read about memory management in Qt and get rid of all those smart pointers at all.