How to (re)call a constructor of an initialised ob

2019-05-07 00:27发布

I'm writing some code that is checking if a specific midi device is plugged in, and if it isn't the code rechecks every 5 seconds until it is plugged in.

My problem comes about in checking the list of devices - the external library has no function to re-check the ports, as it only does it in the constructor of the class.

The only way I could see of getting my code to recheck the list of devices is to re-initialize the class object.

The class object is declared in the header file as ofxMidiIn midiIn;, as it is used globally in the cpp file. The issue is if I 'redeclare' within a function in the cpp it doesn't appear to replace the object in the global scope, even though it is locally fine.

To clarify with pseudocode:

In the .h:

class foo {

    ofxMidiIn midiIn; //first initialization does a port scan

};

in the .cpp:

void foo::setup(){
    midiIn.listPorts(); //if this fails the recheck is triggered every 5 secs
}


void foo::run(){
    //if setup failed then while (!recheck());
}

bool foo::recheck(){

    ofxMidiIn midiIn;
    midiIn.listPorts(); //this works in this (local) scope, but doesn't reassign midiIn globally

}

6条回答
\"骚年 ilove
2楼-- · 2019-05-07 00:33

Use a pointer instead of an instance member

class foo {

    ofxMidiIn* midiIn;

};


foo::foo()
{
    midiIn = new ofxMidiIn;
}

foo::~foo()
{
    delete midiIn;
}

void foo::setup(){
    midiIn->listPorts(); //if this fails the recheck is triggered every 5 secs
}


void foo::run(){
    //if setup failed then while (!recheck());
}

bool foo::recheck(){

    delete midiIn;
    miniIn = new ofxMIdiIn; 

    midiIn->listPorts(); //this works in this (local) scope, but doesn't reassign midiIn globally

}
查看更多
我想做一个坏孩纸
3楼-- · 2019-05-07 00:34

Use a pointer to ofxMidiIn and dynamic allocation when you need to recreate. Make sure you follow the rule of three or inherit from boost::noncopyable.

查看更多
smile是对你的礼貌
4楼-- · 2019-05-07 00:45

By using placement new you can re-call the constructor:

bool foo::recheck()
{
    new (&midiIn) ofxMidiIn();
    midiIn.listPorts(); 
}

The line new (&midiIn) ofxMidiIn() will re-construct midiIn in its own memory region, by calling the constructor of ofxMidiIn. However, this approach will create problem if ofxMidiIn has pointer(s), and you've allocated memory for them in the previous object. You will be leaking memory. You can call the destructor explicitly though, by writing as:

    (&midiIn)->~ofxMidiIn();   //call the destructor explicitly
    new (&midiIn) ofxMidiIn(); //then do this!

Demo : http://ideone.com/OaUtw


Anyway, I believe that better and clean solution would be to make the variable as pointer as:

ofxMidiIn *midiIn;

And then use new and delete. And when you do new for the next time, must delete the previous object by writing as:

bool foo::recheck()
{
    delete midiIn; //must do this if it already has been allocated memory!
    midiIn = new ofxMidiIn();
    midiIn->listPorts(); 
}
查看更多
甜甜的少女心
5楼-- · 2019-05-07 00:49

The reason you're not seeing the updated midiIn is because you're actually creating two instances - one local and one member variable. The local copy in recheck() is shadowing the member variable. On this point, I recommend you crank up your compiler's warning level so that you don't accidentally get burned by this in other places.

Personally I would wrap midiIn in a std::shared_ptr and re-initialize that. Something like this:

#include <memory>

class foo {

std::shared_ptr<ofxMidiIn> midiIn; //first initialisation does a port scan

foo() : midiIn(std::make_shared<ofxMidiIn>() ){} //Constructor

bool recheck(){

midiIn = std::make_shared<ofxMidiIn>(); //Will blow away the old midiIn and replace it with a new one.
midiIn->listPorts(); 
}

};
查看更多
别忘想泡老子
6楼-- · 2019-05-07 00:50

You should not call constructor twice. It may often result in undefined behavior and unmaintainable code.

Rather you copy the content of the constructor code into a class member function only (may be a private) and then call that function when needed. e.g.

class foo {
  void check ()
  {
    // put constructor logic here
  }
public:
  foo ()
  {
    //...
    check();
  }
// now call 'check()` wherever you want
};
查看更多
相关推荐>>
7楼-- · 2019-05-07 00:56

Without knowing anything about this particular class, the immediate solution appears to be assigning.

ofxMidi midiIn;
void function() {
  ofxMidi localMidi;
  if(we_have_our_new_data) 
     midiIn = localMidi;
}

If ofxMidi is not assignable, wrapping the object somehow is appropriate. At the basic level, simply within a pointer.

std::shared_ptr<ofxMidi> midiIn;

void function() {
  std::shared_ptr<ofxMidi> localMidi(new ofxMidi);
  if(we_have_our_data)
    midiIn = localMidi;
}
查看更多
登录 后发表回答