2014-01-15 4 views
1

JNI .cpp 파일에서 SoundTouch * (SoundTouch는 C++ 오디오 처리로 안드로이드 프로젝트에서 사용하기 위해 포장하고 있습니다)가있는 구조체가 있고 초기화합니다 이 같은 전역 개체로서 구조체의 벡터 : 나는 단지 SoundTouchExt 중 하나가 내 프로그램에서 한 번에 객체를 사용 적어도 경우는, 작동전역 객체를 포인터로 초기화하는 것이 성공하는 유일한 방법입니다.

struct SoundTouchExt 
{ 
    SoundTouch* sTouch; 
    queue<signed char>* fBufferOut; 
    int channels; 
    int sampleRate; 
    float tempoChange; 
    int pitchSemi; 
    int bytesPerSample; 

    SoundTouchExt() 
    { 
     sTouch = new SoundTouch(); 
     fBufferOut = new queue<signed char>(); 
    } 
}; 

const int MAX_TRACKS = 16; 

vector<SoundTouchExt> sProcessors(MAX_TRACKS); 

(즉 다른 이야기의 일종이지만, 아마도 관련 - 재생중인 여러 인스턴스로 인해 왜곡 된 결과가 발생 함). 최대한 빨리 잘 컴파일하지만 난 FAULT 11 (독방 감금 오류를) 얻을, 참고로, 포인터를 나는이 SoundTouch sTouch;처럼 선언하는 경우

그러나 new을 주석하고 그에 따라 (.-->를) 그것의 사용을 변경 프로그램이 객체를 사용하려고 시도 할 때 그런 일이 어디

은 다음과 같습니다 약간의 연구와

... 
    SoundTouchExt& soundTouch = sProcessors.at(track); 
    setup(soundTouch, channels, samplingRate, bytesPerSample, tempo, pitchSemi); 
} 

static void setup(SoundTouchExt& soundTouch, int channels, int sampleRate, int bytesPerSample, float tempoChange, float pitchSemi) 
{ 
    SoundTouch& sTouch = soundTouch.sTouch; 

    soundTouch.channels = channels; 
    soundTouch.sampleRate = sampleRate; 
    soundTouch.bytesPerSample = bytesPerSample; 
    soundTouch.tempoChange = tempoChange; 
    soundTouch.pitchSemi = pitchSemi; 

    sTouch.setSampleRate(sampleRate); 
    sTouch.setChannels(channels); 
... 
} 

, 나는 이것이 static intialization order fiasco의 인스턴스가 될 수있다 생각하고 있어요. 라이브러리 소스 코드에 전역 변수가 표시되지 않지만 C++에 대해 충분히 알지 못해서 무엇을 찾아야할지 모릅니다.

내 관찰에서 라이브러리에 대해 제안 할 수있는 것은 무엇입니까 (아니면 올바르게 수행하지 않았을 수 있습니다)?

답변

4

SoundTouch struct/class에 복사 생성자 및/또는 할당 연산자에 문제가 있다고 생각합니다. 또는 당신은 그것들을 쓰지 않았지만 그렇게 할 필요가 없습니다.

SoundTouch 코드가 보이지 않는데 왜 이렇게 말합니까? 음 ...

귀하의 SoundTouchExt은 sTouch 회원 (및 fBufferOut)을 관리하는 방법에 문제가 있습니다. 각 인스턴스는 고유 한 sTouch를 생성하지만 객체를 복사 할 때마다 sTouch 멤버를 처리 할 복사 생성자 또는 할당 연산자가 없습니다. 컴파일러가 제공하는 기본값은 간단한 구성원 별 복사를 수행합니다. 따라서 하나의 SoundTouchExt 객체가 다른 SoundTouchExt 객체에 할당되면 해당 객체는 동일한 SoundTouch를 가리키는 sTouch 포인터로 끝납니다. 나는 당신이 그 일이 일어날 것을 결코 의도하지 않았다. 그러나 할당자를 정리할 소멸자가 없으므로 잠시 동안이 상황을 피할 수 있습니다 (누수 된 메모리는 간과하기 쉽기 때문에).

그리고 vector<SoundTouchExt>을 사용하는 동안 실제로 그 일이 일어나고있는 것처럼 보입니다. 벡터는 내부 배열을 관리합니다. 벡터에 항목을 추가 할 때 현재 배열의 공간이 부족한 경우가 있으므로 추가 항목을 보유 할 새 배열을 만들어야합니다. 이렇게하면 이전 배열의 모든 항목을 새 배열로 복사해야합니다. 즉, SoundTouchExt의 복사 생성자 및/또는 할당 연산자를 사용합니다. 동일한 SoundTouch를 사용하는 두 SoundTouchExt 인스턴스의 상황이 이전 배열에있는 SoundTouch 인스턴스가 파괴되기 전에 잠깐 존재하기 때문에이를 알지 못합니다. 그리고 SoundTouchExt에는 소멸자가 없으므로 아무 문제가 없습니다.

이제 sTouch 멤버가 포인터가 아닌 실제 SoundTouch 인스턴스 일 때 어떻게 변경되는지 고려하십시오. 이 경우 SoundTouchExt 객체가 복사되고 sTouch 멤버가 복사되면 컴파일러는 SoundTouch 복사 생성자/할당 연산자를 사용하게됩니다. 그리고 우리는 당신의 벡터가 그것을 일으킬 수 있음을 알고 있습니다.

SoundTouchExt에는 복사와 관련하여 설명한 문제가 있으므로 SoundTouch에도 문제가 있다고 생각됩니다.그렇다면 sTouch 회원을 사용하려고 할 때쯤에는 아마도 이미 복사되어 문제가 발생했을 것입니다. 그 문제는 당신의 사고로 이어진다.

  • 복사 될 때 모든 관련 객체가 올바르게 작동하는지 확인 :

    그래서 수정하는 일이, 당신은 몇 가지 옵션이 있습니다. 이는 아마도 복사 생성자와 대입 연산자를 구현하는 것을 의미합니다. 그리고 그 경우에는 Rule of Three에 따라 소멸자를 구현해야합니다.

  • 실수로 사용할 수 없도록 복사 생성자와 할당 연산자를 비활성화합니다 (개인용으로 선언하지만 구현하지 마십시오). 그런 다음 벡터 사용과 같은 다른 리팩토링이 필요할 수 있습니다. 사용할 수있는 C++ 11 기능이있는 경우 이동 연산자/생성자를 사용하여 개체를 표준 컨테이너에서 사용할 수 있지만 적절할 경우 해당 멤버를 올바르게 전송할 수 있습니다. 소멸자는 아마도 어느쪽으로 든 여전히 필요합니다.
  • 또는 원시 포인터를 어떤 종류의 스마트 포인터 (예 : unique_ptr)로 바꾸면 추가 코드를 쓰지 않고도 new으로 할당 된 항목을 자동으로 관리 할 수 ​​있습니다.
+0

사실 나는 확실히 하나의 SoundTouch 인스턴스를 가리 키려고하지 않았습니다. 당신은 거의 모든 것에 머리에 완벽하게 못을 박았습니다. 고마워요. –