如何(重新)调用初始化对象的构造函数

How to (re)call a constructor of an initialised object?

本文关键字:对象 构造函数 初始化 调用 重新 如何      更新时间:2023-10-16

我正在编写一些代码,检查是否插入了特定的midi设备,如果没有,代码每5秒重新检查一次,直到它插入。

我的问题是在检查设备列表时出现的——外部库没有重新检查端口的函数,因为它只在类的构造函数中检查端口。

我能看到的让我的代码重新检查设备列表的唯一方法是重新初始化类对象。

类对象在头文件中声明为ofxMidiIn midiIn;,因为它在cpp文件中全局使用。问题是,如果我在cpp中的函数内"重新声明",它似乎不会取代全局作用域中的对象,即使它在局部很好。

用伪代码来澄清:

在。h:

class foo {
    ofxMidiIn midiIn; //first initialization does a port scan
};

.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
}

通过使用placement new,您可以重新调用构造函数:

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

new (&midiIn) ofxMidiIn()将通过调用ofxMidiIn的构造函数在自己的内存区域中重构midiIn。但是,如果ofxMidiIn有指针,并且您已经在前面的对象中为它们分配了内存,那么这种方法将会产生问题。你将会泄漏内存。你可以显式地调用析构函数,这样写:

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

Demo: http://ideone.com/OaUtw


无论如何,我相信更好和干净的解决方案是使变量为指针为:
ofxMidiIn *midiIn;

然后使用newdelete。当您下次执行new时,必须通过如下方式删除前一个对象:

bool foo::recheck()
{
    delete midiIn; //must do this if it already has been allocated memory!
    midiIn = new ofxMidiIn();
    midiIn->listPorts(); 
}

不应该两次调用构造函数。它可能经常导致未定义的行为和不可维护的代码。

而是将构造函数代码的内容复制到类成员函数中(可能是private),然后在需要时调用该函数。例如

class foo {
  void check ()
  {
    // put constructor logic here
  }
public:
  foo ()
  {
    //...
    check();
  }
// now call 'check()` wherever you want
};

使用指针代替实例成员

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
}

在不了解这个特定类的情况下,立即的解决方案似乎是赋值。

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

如果ofxMidi不可赋值,以某种方式包装对象是合适的。

std::shared_ptr<ofxMidi> midiIn;
void function() {
  std::shared_ptr<ofxMidi> localMidi(new ofxMidi);
  if(we_have_our_data)
    midiIn = localMidi;
}

在需要重新创建时使用指向ofxmidin的指针和动态分配。请确保遵循三个规则或继承boost::noncopyable

没有看到更新的midin的原因是您实际上创建了两个实例—一个本地实例和一个成员变量。recheck()中的本地副本遮蔽了成员变量。在这一点上,我建议您调高编译器的警告级别,这样您就不会在其他地方意外地被此问题烫伤。

我个人会将midin封装在std::shared_ptr中并重新初始化它。像这样:
#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(); 
}
};