Итерация по каждому объекту в классе - PullRequest
1 голос
/ 05 октября 2011

Из-за характера игры, которую я делаю, мне нужно иметь возможность создавать объекты на лету случайным образом.Мне нужно иметь возможность изменять переменные всех существующих в настоящее время объектов класса 60 раз в секунду.

Мне сказали, что хотя C ++ не способен к отражению, я мог бы передавать адресаобъекты к вектору.К сожалению, я просто немного смущен тем, как это сделать.Есть ли лучшее решение?Если нет, то может ли кто-нибудь предоставить пример кода?

tl; dr?Мне нужно запустить функцию для переменных всех объектов в классе.Howdo

Ответы [ 4 ]

3 голосов
/ 05 октября 2011

«Передать адрес объекта в вектору» звучит так

std::vector<MyObject *> objectAddresses;

Это вектор указателей на MyObject. Обратите внимание, что вы должны добавлять и удалять указатели вручную. Невозможность удалить указатель объекта из этого вектора при его удалении может легко привести к сбою вашей программы.

В зависимости от требований к производительности, вы можете выбрать контейнер STL, отличный от вектора. Векторы сделают вашу итерацию очень быстрой, но удаление объекта из произвольной позиции в векторе будет дорогостоящим. Без предварительного знания его положения в векторе это также будет сложно. Рассмотрим std :: set.

http://www.cplusplus.com/reference/stl/ перечисляет контейнеры, предоставляемые stl, и приблизительно описывает их производительность.

Когда у вас есть контейнер с указателями, просто зацикливайтесь на каждой записи и вызывайте функцию. Возможно, вам понадобится разыменование дважды, например (* Itor) -> FUNC ()

.

Может быть, это просто ваша терминология, но у меня есть более одного объекта, и Я не понимаю, как это будет работать. Разум идет дальше вглубь? Я думаю, что это должно быть больше по линии std :: vector objectAddresses;

Если вы объявляете class MyClass, вы должны сказать vector<MyClass*>. Если вы объявите class MyObject, скажите vector<MyObject*>. Это будет то же самое для компилятора, поэтому используйте тот, который вам удобнее читать.

std :: vector - это не то, что большинство графических программистов считает вектором (например, 3 значения, обозначающие положение в трехмерном пространстве). Это самоизменяющийся массив. Поэтому, когда вы добавляете значения в вектор (с помощью метода push_back), он проверяет, достаточно ли он выделил памяти для хранения дополнительных значений, и перераспределяет больший блок памяти при необходимости.

class MyClass
{
  public:
    static std::vector<MyClass *> objAddrs;
    MyClass()
    {
      objAddrs.push_back(this);
    }
    ~MyClass()
    {
      // Find this in objAddrs & objAddrs.erase()
    }

    void doWork()
    {
      // something useful here
    }
};

Будет вызывать каждый экземпляр MyClass добавлять свой собственный адрес в конец objAddrs при создании. Помните, что деструктор должен удалить тот же адрес!

for(std::vector<MyObject *>::iterator itor=MyClass::objAddrs.begin(); itor!=MyClass::objAddrs.end(); ++itor)
{
  (*itor)->doWork();
}

Будет вызывать функцию doWork () для каждого существующего экземпляра MyObject (). Если какие-либо объекты MyObject были уничтожены, а деструктор не может их удалить, разыменованный указатель будет разыменован и будет вызвано неопределенное поведение (возможно, segfault).

std :: set позволяет удалить по значению:

class MyClass
{
  public:
    static std::set<MyClass *> objAddrs;
    MyClass()
    {
      objAddrs.insert(this);
    }
    ~MyClass()
    {
      objAddrs.erase(this);
    }
};
1 голос
/ 05 октября 2011

Я предполагаю, что вы хотите получить способ перебора всех экземпляров класс, который в настоящее время существует, не проходя хлопот управлять хранилищем самостоятельно. SelfStore предназначен в качестве базы класс для такой функциональности. Он использует list внутри, потому что я Предположим, что объекты создаются и удаляются часто. Вы можете захотеть переключитесь на другой тип хранилища, который больше подходит вашему варианту использования. итератор сохраняется в качестве члена для быстрого удаления, но может быть выполнен без, если дополнительная память является проблемой. Это все еще нужно немного (много) настройка, например личное хранилище и статика begin end, нет изменяемый доступ, скрытие типа хранилища через typedefs и т. д. не потокобезопасен. SelfStore это всего лишь шаблон, потому что он может прийти пригодится.

#include <iostream>
#include <list>

template<typename T>
class SelfStore
{
  typename std::list<SelfStore*>::iterator it;

public:
  SelfStore() {
    store.push_back(this);
    it = --end(store);
  }

  virtual ~SelfStore() {
    store.erase(it);
  }

  static std::list<SelfStore*> store;
};

template<typename T>
std::list<SelfStore<T>*> SelfStore<T>::store = std::list<SelfStore<T>*>();


struct Foo : public SelfStore<Foo> {

};


int main()
{
  {
  Foo f, g, h;
  std::cout << SelfStore<Foo>::store.size() << std::endl;
  }

  Foo a, b;
  std::cout << SelfStore<Foo>::store.size() << std::endl;
  return 0;
}
0 голосов
/ 05 октября 2011

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

Я предлагаю создать visitor метод, который принимает функтор и применяет его к каждому элементу данных.

Переполнение стека поиска для шаблона проектирования Visitor.

0 голосов
/ 05 октября 2011

В конструкторе ваших объектов добавьте их в глобальный статический список объектов (не забудьте удалить объект в деструкторе!). Это позволит вам найти объекты и манипулировать ими. Если ваша программа многопоточная, вам понадобится способ синхронизировать доступ к списку и объекту, которым вы управляете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...