DynamicArray выдает исключение OutOfBounds - PullRequest
1 голос
/ 03 февраля 2009

Я знаю, это может звучать странно, но да, это 2009 год, и мне нужно написать небольшое приложение с использованием BCB5 :)

Проблема в том, что DynamicArray выдает исключение OutOfBound при попытке развернуть его из рабочего потока.

У меня есть глобальная переменная, скажем,

DynamicArray<double> X;

В основном потоке я проверяю длину массива и получаю 0, что нормально (длина не установлена)

Application->MessageBox(itoa(X.Length,str , 10), "", MB_OK);

Ниже приведен класс моего рабочего потока

class ArrayModifierThread : public TThread
{
private:
DynamicArray<double> __thread X;

protected:
void __fastcall Execute();

public:
__fastcall ArrayModifierThread(bool CreateSuspended);
 void setX(DynamicArray<double> &a);
};

Пока все хорошо. Далее я создаю новую тему:

ArrayModifierThread *t = new ArrayModifierThread(true);
t->setX(X); // Pass reference to my global DynamicArray
t->Resume();

Здесь выполняется метод Execute ():

void __fastcall ArrayModifierThread::Execute()
{
 X.Length = 10;
 X[5] = 45.5;
}

Я ожидаю, что глобальный массив будет расширен, а шестой элемент получит значение 45,5.

Но более тщательное исследование из основного потока дает длину = 0 и исключение ArrayOfBounds:

 Application->MessageBox(itoa(__X.Length,str , 10), "", MB_OK);
 Application->MessageBox(itoa(__X[5],str , 10), "", MB_OK);

Может кто-нибудь сказать мне, что я пропустил?

Ответы [ 3 ]

1 голос
/ 03 февраля 2009

Это не будет работать, так как член X не является ссылкой. Когда вы вызываете set (), вы делаете локальную копию объекта, затем Execute () изменяет локальную версию.

class ArrayModifierThread : public TThread
{
    private:
        DynamicArray<double> __thread X;


void __fastcall ArrayModifierThread::Execute()
{
    X.Length = 10;
    X[5] = 45.5;
 }

Существует три альтернативных решения:

Сделайте вашу локальную переменную-член X ссылкой.
Поскольку ссылка должна быть инициализирована при построении, вы не можете использовать set () для ее изменения, поэтому передайте ссылку конструктору вашего объекта и сохраните ее там.

Сделайте вашу локальную переменную-член X указателем. При использовании set () принимайте адрес переданного параметра (обратите внимание, что это ссылка, поэтому вы получите адрес объекта, на который он ссылается). Это также означает, что необходимо выполнить execute, чтобы учесть, что X является указателем.

Не использовать локальную переменную-член. Просто измените глобальный напрямую.

1 голос
/ 03 февраля 2009

В вашем методе Execute вы изменяете поле X потока , а не глобальную переменную X. Хотя метод setX получает аргумент по ссылке, переменная-член не является ссылкой. В нем хранится копия значения DynamicArray, а изменение свойства Length гарантирует, что оно ссылается на уникальный массив.

Функция setX получает ссылку на глобальную переменную, как вы правильно заметили в своем "ответе", но она не сохраняет ссылку на нее. Вместо этого он копирует его, когда назначает поле X объекта.

Возможно, вы намеревались также объявить X в качестве ссылки:

private:
  DynamicArray<double>& X;

Это может сработать. Ваша setX функция больше не будет работать, так как вам не разрешено «пересаживать» ссылку после ее инициализации. Вместо этого вам нужно инициализировать его в конструкторе потока:

ArrayModifierThread(DynamicArray<double>& a): X(a) { ... }

Вы также можете хранить указатель на массив вместо ссылки:

private:
  DynamicArray<double>* X;
public:
  void setX(DynamicArray<double>& a) {
    X = &a;
  }
protected:
  void Execute() {
    X->Length = 10;
    (*X)[5] = 45.5;
  }

Еще кое-что, о чем вам нужно знать, это то, что ваш код не является поточно-ориентированным. (Здесь нет и моего.) У вас есть несколько потоков, модифицирующих один и тот же общий ресурс (массив) без какой-либо защиты, например, критического раздела. Это выходит за рамки этого вопроса, хотя. Сначала найдите «Переполнение стека» и остальную часть Интернета, а затем вернитесь, чтобы задать новый вопрос , если вам потребуется помощь в решении этой проблемы.

0 голосов
/ 03 февраля 2009

Ну, это не совсем понятно для меня. Я думал, что из-за void setX (DynamicArray & a) рабочий поток получает ссылку на глобальную переменную.

Не могли бы вы опубликовать пример кода, как это должно быть сделано?

Вот так выглядит моя пустота setX (DynamicArray & a):

void ArrayModifierThread::setX(DynamicArray<double> &a)
{
   X = a;
}
...