Как (пере) вызвать конструктор инициализированного объекта? - PullRequest
4 голосов
/ 29 июля 2011

Я пишу некоторый код, который проверяет, подключено ли определенное MIDI-устройство, и если это не так, код проверяется каждые 5 секунд, пока оно не будет подключено.проверка списка устройств - во внешней библиотеке нет функции для повторной проверки портов, поскольку она делает это только в конструкторе класса.

Единственный способ заставить мой код перепроверитьСписок устройств предназначен для повторной инициализации объекта класса.

Объект класса объявлен в заголовочном файле как ofxMidiIn midiIn;, так как он используется глобально в файле cpp.Проблема в том, что если я 'redeclare' внутри функции в cpp, он не заменяет объект в глобальной области видимости, даже если это локально нормально.1011 * В .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

}

Ответы [ 6 ]

10 голосов
/ 29 июля 2011

Используя placement new, вы можете повторно вызвать конструктор:

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

Строка new (&midiIn) ofxMidiIn() восстановит midiIn в своей области памяти, вызвав конструктор ofxMidiIn.Однако этот подход создаст проблему, если ofxMidiIn имеет указатель (и), и вы выделили память для них в предыдущем объекте.У тебя будет утечка памяти.Вы можете явно вызвать деструктор, написав:

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

Демо: http://ideone.com/OaUtw


В любом случае, я считаю, что лучшим и чистым решением было бы создание переменнойкак указатель как:

ofxMidiIn *midiIn;

А затем используйте new и delete.А когда вы делаете new в следующий раз, необходимо удалить предыдущий объект, написав:

bool foo::recheck()
{
    delete midiIn; //must do this if it already has been allocated memory!
    midiIn = new ofxMidiIn();
    midiIn->listPorts(); 
}
1 голос
/ 29 июля 2011

Использовать указатель вместо члена экземпляра

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

}
0 голосов
/ 29 июля 2011

Причина, по которой вы не видите обновленный midiIn, заключается в том, что вы фактически создаете два экземпляра - один локальный и одну переменную-член. Локальная копия в recheck () скрывает переменную-член. На этом этапе я рекомендую вам повысить уровень предупреждения вашего компилятора, чтобы вы случайно не сгорели от этого в других местах.

Лично я бы обернул midiIn в 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(); 
}

};
0 голосов
/ 29 июля 2011

Не зная ничего об этом конкретном классе, кажется, что немедленное решение присваивается.

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;
}
0 голосов
/ 29 июля 2011

Используйте указатель на ofxMidiIn и динамическое выделение, когда вам нужно пересоздать. Убедитесь, что вы следуете правилу трех или наследуете от boost :: noncopyable.

0 голосов
/ 29 июля 2011

Вы не должны вызывать конструктор дважды . Это может часто приводить к неопределенному поведению и не поддерживаемому коду.

Вместо этого вы копируете содержимое кода конструктора только в функцию-член класса (может быть private), а затем вызываете эту функцию при необходимости. например, * +1008 *

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