Инициализация глобальных объектов в качестве указателя является единственным способом, который успешно

В файле JNI .cpp у меня есть структура с SoundTouch * (SoundTouch — это обработка звука C ++, которую я обертываю для использования в проекте Android), и я инициализирую вектор структур как глобальные объекты, подобные этому:

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);

Это работает, по крайней мере, если я использую только один из объектов SoundTouchExt за раз в моей программе (это своего рода другая история, но, возможно, связанная — с несколькими экземплярами в игре вызывает искаженный вывод).

Однако, если я объявлю это так SoundTouch sTouch;закомментируйте new и измените его использование соответствующим образом ( -> в .), указатели на ссылки, я компилирую нормально, но я получаю ОШИБКУ 11 (ошибка сегмента), как только программа пытается использовать объект.

Вот где это происходит:

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

После небольшого исследования я думаю, что это может быть статический порядок инициализации фиаско. Я не вижу глобальных переменных в исходном коде библиотеки, но я не знаю достаточно о C ++, чтобы знать, что еще искать.

Что моё наблюдение может подсказать по поводу библиотеки (или, может быть, я что-то не так делаю)?

1

Решение

Я верю твоему SoundTouch Структура / класс имеет проблему в своем конструкторе копирования и / или операторе присваивания. Или вы даже не написали их, но нужно.

Почему я говорю это, когда я даже не вижу код для SoundTouch? Что ж…

Ваш SoundTouchExt есть проблемы с тем, как он управляет своим членом sTouch (и fBufferOut также). Каждый экземпляр создает свой собственный sTouch, но у вас нет конструктора копирования или оператора присваивания, чтобы иметь дело с членами sTouch, когда ваши объекты копируются. Значения по умолчанию, предоставленные компилятором, просто сделают поверхностную копию для каждого члена. Таким образом, если один объект SoundTouchExt когда-либо будет назначен другому, то оба они получат указатели sTouch, указывающие на один и тот же SoundTouch. Я сомневаюсь, что ты когда-нибудь хотел, чтобы это произошло. Однако, поскольку у вас также нет деструктора для очистки этих выделений, вы можете на время обойтись без этой ситуации (поскольку утечка памяти будет легко пропустить).

И похоже, что вам действительно случается, чтобы сойти с рук во время использования vector<SoundTouchExt>, Вектор управляет внутренним массивом. Когда вы добавляете записи в вектор, ему иногда может не хватать места в его текущем массиве и, следовательно, необходимо создать новый массив для хранения дополнительной записи. При этом он должен скопировать все записи из старого массива в новый. Так что используется конструктор копирования и / или оператор присваивания SoundTouchExt. Вы не замечаете этого, потому что ситуация двух экземпляров SoundTouchExt, использующих один и тот же SoundTouch, существует только на короткое время, прежде чем один из старого массива будет уничтожен. А поскольку в SoundTouchExt отсутствует деструктор, проблема не возникает.

Теперь рассмотрим, как все меняется, когда элемент sTouch является фактическим экземпляром SoundTouch, а не указателем. В этом случае, когда объект SoundTouchExt копируется и, таким образом, копируется элемент sTouch, это означает, что компилятор будет использовать конструктор копирования / оператор присваивания SoundTouch. И мы знаем, что ваш вектор может вызвать это.

Поскольку у вашего SoundTouchExt есть проблемы, которые я описал при копировании, я подозреваю, что у вашего SoundTouch также есть проблемы. Если это так, то к тому времени, когда вы попытаетесь использовать элемент sTouch, он, вероятно, уже был скопирован и, таким образом, вызвал какую-то проблему. Эта проблема приводит к вашей аварии.

Итак, чтобы исправить положение, у вас есть несколько вариантов:

  • Убедитесь, что все соответствующие объекты действуют правильно при копировании. Это, вероятно, означает реализацию конструкторов копирования и операторов присваивания. И в этом случае вам, скорее всего, следует реализовать деструктор, согласно Правило трех.
  • Или отключите их конструкторы копирования и операторы присваивания (объявите их как частные, но не реализуйте), чтобы их нельзя было случайно использовать. Это может потребовать некоторого другого рефакторинга, такого как использование вектора. Хотя, если у вас есть функции C ++ 11, вы можете использовать операторы / конструкторы перемещения, чтобы ваши объекты могли работать в стандартных контейнерах, как они делают сейчас, но при необходимости правильно передавать свои элементы. Деструктор, вероятно, все еще необходим в любом случае.
  • Или замените эти необработанные указатели на определенные виды интеллектуальных указателей (например, unique_ptr), которые могут автоматически управлять всем, что выделено new без необходимости писать какой-либо дополнительный код.
4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]