2014-11-26 9 views
3

У меня есть std::vector<Enemy*> enemies, и когда я создаю новый Enemy, я делаю enemies.push_back(this). Это работает на то, что я делаю, но мне интересно, есть ли способ, чтобы вектор не нуждался в указателях противников. Я пробовал только std::vector<Enemy>, но, похоже, это вызывает множество проблем, которые я не могу понять.C++ вектор без указателей

т.е. - пришлось изменить на enemies.push_back(*this), и по какой-то причине это вызвало некоторые ошибки компоновщика.

пробегает по следующим работам, но удаление указателей создает проблемы:

void Enemy::updateEnemies(sf::RenderWindow &window) { 
    for(std::vector<Enemy*>::iterator it = enemies.begin(); it < enemies.end(); it++) { 
     (*it)->update(window); 
    } 
} 

интересно, если кто-то может мне точку в направлении с использованием вектора без указателей и петель через него, обновление объектов внутри него с той же функцией.

+0

Почему вы делаете 'push_back (this)' и что заставило вас поверить, что решение было 'push_back (* this)'? Это отсутствует в вашем вопросе ... и на C++ 11 используйте интеллектуальные указатели. –

+0

- это не то, как вы добавляете что-то в вектор? исходя из javascript, 'array.push()' обычно - это то, как я делал. –

+0

Я не понимаю, почему вам нужно делать push_back (** this **) (акцент на 'this'). –

ответ

1

Моя практика заключается в том, чтобы убедиться, что класс реализует (и делает public) все следующие: конструктор по умолчанию, конструктор копирования, оператор присваивания и деструктор. Тогда нет проблем с вещами вроде std::vector<Enemy>. (Конструктор по умолчанию даже не требуется для векторов, но может быть полезно для различных других вещей.)

Одно предостережение, хотя: когда вы push_back()Enemy в свой вектор, это на самом деле копия исходного экземпляра который хранится. Это вызывает несколько ошибок: во-первых, изменения в оригинале (например, данные элемента переменной e в области main() моего примера ниже) не повлияют на копию, хранящуюся в векторе. Если вы привыкли работать с указателями-указателями, это может быть удивительно. Во-вторых, неявное построение копий и копирование данных членов потребует времени, которое может или не может оказать существенного влияния на производительность. В-третьих, неявное построение и копирование могут вызвать побочные эффекты (вы должны просто избегать их в своем дизайне, где это возможно).

Вот пример:

#include <vector> 
#include <iostream> 

class Enemy 
{ 
    public: 
    Enemy() : mEvilness(1) {} // default (i.e. parameterless) constructor 
    Enemy(const Enemy& other) { Copy(other); } // copy constructor 
    Enemy& operator=(const Enemy& other) { return Copy(other); } // assignment operator 
    ~Enemy() {} // destructor 

    Enemy(int evilness) : mEvilness(evilness) {} // standard constructor 

    void Gloat(void) const 
    { 
     std::cout << "muahaha"; 
     for(int i = 0; i < mEvilness; i++) std::cout << "ha"; 
     std::cout << "!\n"; 
    } 

    int mEvilness; 

    private: 

    // common helper method for copy constructor and assignment operator: 
    Enemy& Copy(const Enemy& other) 
    { 
     mEvilness = other.mEvilness; // make copies of any other member data here 
     return *this; 
    } 
}; 


typedef std::vector<Enemy> EnemyHorde; 

void AllGloat1(const EnemyHorde& h) // doesn't matter if you pass by reference... 
{ 
    for(EnemyHorde::const_iterator it = h.begin(); it != h.end(); it++) 
     it->Gloat(); 
} 

void AllGloat2(EnemyHorde h) // ...or value (but this will take more CPU time) 
{ 
    for(EnemyHorde::const_iterator it = h.begin(); it != h.end(); it++) 
     it->Gloat(); 
} 

int main(int argc, const char* argv[]) 
{ 
    EnemyHorde h; 
    Enemy e(1); 
    h.push_back(e); 
    h.push_back(Enemy(2)); // even transient Enemy instances get copied and stored 
    h.push_back(Enemy(3)); 

    AllGloat1(h); 
    std::cout << "\n"; 

    e.mEvilness++; // this will have no effect on the output because h contains a *copy* of e 

    AllGloat2(h); 

    return 0; 
} 
+1

Вам не нужен конструктор по умолчанию (без параметров) для 'vector ' для компиляции. –

+0

Полезно знать. Я думаю, что у меня всегда была привычка включать одну, потому что есть много других ситуаций, для которых это полезно (например, «Enemy * Sparta = new Enemy [300];»). В моем примере выше определения конструктора можно, конечно, также сокращать, используя значение по умолчанию, и часто это имеет наибольший смысл: «Враг (int evilness = 1): mEvilness (evilness) {}' – jez

0

Вам не нужно указатели (большую часть времени) в C++.

Копия будет сделана при использовании метода std::vector::push_back().

Пример:

Enemy evil_wizard; 
std::vector<Enemy> enemy_container; 
enemy_container.push_back(evil_wizard); 
Enemy Evil_knight; 
enemy_container.push_back(Evil_knight); 
Enemy pink_elephant; 
enemy_container.push_back(pink_elephant); 
1

Everbody говорит об этом в комментариях - но сво использовать ответ

умные указатели

если вы не знаете, как это сделать, чтобы потом Google

Вы жизнь намного проще, безопаснее, быстрее, ...

И они очень просты в использовании - основной трюк с их использованием - доверять им и не пытаться получить умные или «помочь» им.

1

Если вы хотите получить обоснованный ответ, вам нужно сделать один шаг назад - к дизайн. Насколько я вижу, объекты Enemy регистрируются через конструктор в виде глобального списка. Все идет нормально.

Но как производится этот объект?В этом примере в Врага можно построить везде

  • На стеке как локальный
  • По новым()
  • умный указатель
  • В качестве элемента в векторе, список, DEQUE ...
  • ...

В зависимости от этого, объект Enemy-object can not делает какие-либо надежные заявления о его хранении. Но одно, что все объекты разделяют и что всегда доступно изнутри объекта - это адрес («это»). Таким образом, решение с помощью указателя является единственным решением, универсальным для всех объектов Enemy. (Ссылки в этом контексте также «своего рода указатель», а другие более сложные конструкции могут также опираться на указатели).

std :: vector can not work, потому что вы получаете 2 разных объекта. Изменить один из них не влияет на другое. Это не сработает. И невозможно переключиться на интеллектуальные указатели без изменения дизайна.

Есть 2 общих решения:

Управление распечатки с «внутри» Врага в общем образом, как в данном примере. Расширяемый с большим количеством функций, таких как записи автоматического удаления через деструктор .....

Управление листингом из «снаружи». Вражеские объекты не регистрируются, генератор объектов-врагов несет ответственность за выполнение этого (шаблон проектирования «завод» является хорошим решением в этом случае). И вы можете использовать интеллектуальные указатели, что является хорошей идеей в большинстве случаев.

Есть еще несколько решений (включая некоторые хорошие решения), которые не имеют значения, они превышают объем вопроса.

Смежные вопросы