2012-08-11 4 views
0

일부 데이터에 맞는 최소 제곱을 실행하는 프로그램이 있습니다. 이 절차는 별도의 스레드에서 실행되며 대화 상자에서 제어됩니다. 이 대화 상자에는 피팅 업데이트와 최종 보고서를 보여주는 QPlainTextEdit가 있습니다.QPlainTextEdit throwing std :: bad_alloc

대화 상자는 Qt 디자이너에서 만들어졌으며, 코드는 QtCreator로 실행되고 Qt 버전은 4.8.1입니다.

내가 겪고있는 문제는 다소 불규칙합니다. 처음 절차를 실행하면 모든 것이 잘됩니다. 내가 다시 실행할 경우, 때때로 프로그램이 메시지

과 충돌이 '표준 : : bad_alloc 뿐이다' 의 인스턴스를 던지는 후 호출 종료 무엇을() : 표준 : : bad_alloc 뿐이다 프로그램이 예기치 않게 종료되었습니다.

QPlainTextEdit의 clear() 메서드 호출로 문제를 추적했습니다. 여기에 몇 가지 코드가 있습니다.

// Snippets of the class definition 
class QLSQDialog : public QDialog, public Ui_QLSQDialog 
{ 
    Q_OBJECT 
public: 
    QLSQDialog(QWidget *parent = 0); 
    (...) 
    void UpdateDisplay(const QString &msg, int iter, double norm); // Update values of chi, etc on displays 
signals: 
    void Run();   // Signal to run a LSQ procedure 
    (...) 
private slots: 
    void on_btnRun_clicked(); 
    (...) 
private: 
    void Enables(bool running); // Enable and disable features depending on running state of LSQ fit 
    (...) 
}; 


// Snippets of the class implementation 

QLSQDialog::QLSQDialog(QWidget *parent) : QDialog(parent) 
{ 
    setupUi(this);   // Set up dialog 
    (...) 
    txtInfo->clear(); // txtInfo is a QPlainTextEdit created in Designer 
    (...) 
} 

void QLSQDialog::UpdateDisplay(const QString &msg, int iter, double norm) 
{ 
    lblChi->setText(QString::number(norm,'f',12)); 
    if (iter >= 0) lblIt->setText(QString::number(iter)); 
    txtInfo->appendPlainText(msg); 
} 

void QLSQDialog::on_btnRun_clicked() 
{ 
    txtInfo->clear(); // Offending line in second run 
    Enables(true); 
    emit Run(); 
} 

void QLSQDialog::Enables(bool running) 
{ 
    bool Idle = !running; 
    bool HasReport = !txtInfo->document()->isEmpty(); 
    (...) 
    btnReport->setEnabled(Idle && HasReport); 
} 

txtInfo은 QPlainTextEdit 개체입니다. 객체가 일 때 빈 텍스트 편집을 표시하기 위해 txtInfo->clear()을 호출합니다. '실행'도구 버튼을 클릭하면 기본 슬롯에서 새 스레드를 시작하는 실행 신호를 내 보냅니다. txtInfo QPlainTextEdit는 완료 될 때까지이 스레드에서 업데이트됩니다 (사실 스레드는 주 응용 프로그램에 걸려있는 신호를 내고 차례로 UpdateDisplay을 호출 함).

두 번째로 실행 버튼을 클릭하면 충돌과 오류가 발생합니다. txtInfo->clear(), txtInfo->document()->clear(), 또는 txtInfo->setPlainText("") 또는 txtInfo->document()->setPlainText("")을 바꾸면 문제가 동일합니다 (두 번째 실행시 충돌). 때때로, 자주는 아니지만, 충돌하기 전에 몇 번 (10의 순서로) 실행할 수 있습니다.

마지막으로, 내가 txtInfo->clear() 라인을 주석 처리하면, 시도한만큼 루틴을 실행할 수 있습니다 (한 번의 테스트에서 약 80 회 실행 한 후 피곤함).

내 유일한 (거의 임의적 인) 추측은 문제가 어떻게 든 스레드에서 업데이트와 관련이 있다는 것입니다 (즉, catch 된 신호를 내고 차례로 UpdateDisplay 함수를 호출 함). 필자가 생각하는 이유는 신호를 주석 처리하고 그냥 가짜 정보로 UpdateDisplay을 호출하는 새 버튼을 만들면 모든 것이 잘된다는 것입니다.

qApp->processEvents() 위의 공격 라인은 효과가 없습니다.

여기에 붙어 있습니다. 어떤 아이디어라도 환영합니다. 예를 들어, clear() 메서드를 호출하는 것이 ok인지 확인하기 위해 수행 할 수있는 테스트가 있습니까?

+1

스레드에서'QWidget' 메서드를 호출하지 않아야합니다. 스레드로부터 안전하지 않습니다. 메인 GUI 스레드가 볼 수 있도록 신호를 내 보내야하고 메서드를 호출하여 직접 응답해야합니다. – jdi

+0

실로, 당신 말이 맞아요. 나는 그 일에 곤경에 처했습니다. 내 설명이 조금 부족했다. 스레드에서 실행되는 작업자 개체가 있습니다. 업데이트 매개 변수로 신호를 내 보냅니다. 그 신호는 UpdateDisplay를 호출하는 주 앱에 의해 감지됩니다. 나는 이것을 지적하기 위해 질문을 편집했다. – rpsml

답변

0

마침내이 문제를 코드에서 불쾌한 메모리 누수로 추적했습니다. 나는 코드를 "고쳤습니다"그러나 나는 문제가 왜 일어나고 있었는지에 의아해하면서 조금 혼란 스럽습니다.

기본적으로 나는 큰 vector<double>을 생성하고 그 주소를 vector<double> * 변수를 호출하는 함수에 전달했습니다. 문제는 원래의 벡터가 기능이 끝나기 전에 중단 된 것이 었습니다. 고전적인 벙어리 실수. 아마도 QPlainTextEdit 문서는 vector<double>이었던 영역에 공간을 할당하고있었습니다 : 예기치 않은 동작이 예상됩니다. 그러나 나는 추락을 기대하지 않을 것이다.

벡터는 "읽기 전용"입니다.함수를 사용하여 값을 읽고 계산을 다른 어딘가에 저장했습니다. 이제 일반 텍스트가 이전에 vector<double>에 의해 지정된 메모리에 무언가를 생성한다고 가정 해 봅시다. 이 경우, 내가 QPlainTextEdit::clear() 일반 텍스트 문서, 벡터 변경에 의해 이전에 가리킨 값과 나는 계산이 아닌 의미가 기대합니다. 함수가 지금 죽은 포인터 vector<double>에 액세스 할 때 나는 또한 충돌을 받아 들일 것이다. 하지만 텍스트를 지우면 프로그램이 다운되는 것을 기대하지 않을 것입니다. 텍스트는 결국 유효한 포인터입니다.

어쨌든 누군가가있는 경우 충돌이 발생하는 이유를 알고 싶습니다. 그러나 그렇지 않으면 누수가 수리되면 문제가 사라집니다. 물론 그 이유를 아는 것은 누설을 수리하지 않을 변명의 여지가 없습니다.

+0

해당 벡터에 대한 호출을 으로 묶고 크기가 어설 션이므로 비어 있지 않아야합니다. – linello

+0

좋은 조언입니다. 그러나 아직도 나를 괴롭히는 것은 사망자가 사망 한 벡터에 접근하는 것이 아니라 새로 태어난 텍스트를 수정하는 것입니다. – rpsml

관련 문제