2016-07-06 2 views
0

Я упростил код как можно больше. Поэтому у меня есть два класса:Указатель на вектор не указывает

class EntityManager 
{ 
    public: 
     std::shared_ptr<std::vector<Entity> > getEntities() 
     { 
      return std::make_shared<std::vector<Entity> >(m_entities); 
     } 

    private: 
     std::vector<Entity> m_entities{}; 
}; 

и

class System 
{ 
    public: 
     void loadEntities(std::shared_ptr<std::vector<Entity> > entities) 
     { 
      m_entities = entities; 
     } 

    private: 
     std::shared_ptr<std::vector<Entity> > m_entities; 
}; 

Сейчас в основном я хочу m_entities Системы, чтобы указать на m_entities из EntityManager.

Я сделал это:

system = System(); 
system.loadEntities(m_entityManager.getEntities()); 

Но тогда я отодвинул элемент в m_entities вектор EntityManager и этот элемент не был добавлен в m_entities вектор системы, что означает, что мой указатель не указывает ,

Где моя ошибка?

Спасибо!

+1

Простой код хорош, но он все равно должен быть полным. Читайте снова о том, как построить [MCVE]. –

+3

Не думайте, что вам нужен общий указатель. 'EntityManager' является очевидным владельцем списка сущностей, и он уверен, что' System' владеет 'EntityManager'. Все права собственности и срок службы должны быть известны. – user4581301

+0

Что вы имеете в виду, должно быть известно? И что вы предлагаете использовать? – Urefeu

ответ

2

Ваша проблема эта линия: return std::make_shared<std::vector<Entity> >(m_entities);

Что происходит, что shared_ptr управляет новый std::vectory<Entity> контейнер, который инициализируется в качестве копии m_entities. Поэтому изменение экземпляра в shared_ptr не изменяет элемент данных в классе EntityManager, и, конечно, shared_ptr не увидит изменений, внесенных в EntityManager::m_entities.

+0

Спасибо. Есть ли способ решить эту проблему с помощью shared_ptr? – Urefeu

+0

@Urefeu Да, но нет смысла. Вам не нужен общий указатель. – user4581301

+0

@Urefeu Почему навязчивая идея с shared_ptr здесь? –

2

std::make_shared не «разделяет эту вещь»; он «делает то, что будет разделяться».

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

Ваш код динамически распределяет std::vector, копия построена из m_entities и управляется std::shared_ptr. Это сокращенная для этого:

std::vector<Entity>* ptr_to_copy = new std::vector<Entity>(m_entities); 
return std::shared_ptr(ptr_to_copy); 

Это не ясно, что вы пытаетесь сделать, от кода, который (по собственному признанию) не достигает этой цели. Но кажется маловероятным, что здесь подходит std::shared_ptr.

Если это так, сделайте вектор динамически распределенным и общим с самого начала; в противном случае просто верните ссылку на вектор как есть.

+0

Я немного потерялся с использованием разных указателей. Когда следует использовать сырые, общие, уникальные ...? – Urefeu

+0

@Urefeu Изучите другие вопросы по этой же теме, а затем, возможно, задайте новый вопрос. –

+0

@Urefeu Крытый здесь: http://stackoverflow.com/questions/8706192/which-kind-of-pointer-do-i-use-when Имена немного изменились с этой должности, но логика по-прежнему сохраняется. – user4581301

0

Взломать пример без указателей.

#include <string> 
#include <iostream> 
#include <vector> 

//Hack-sample Entity class 
class Entity 
{ 
    public: 
     Entity(const char * name): m_name(name) 
     { 

     } 
     void print() // this is stupid in real life. Prefer a << overload 
     { 
      std::cout << "Hi! I'm " << m_name << "!\n"; 
     } 
    private: 
     std::string m_name; 
}; 

class EntityManager 
{ 
    private: 
     std::vector<Entity> m_entities; 

    public: 
     // hide the fact that a vector is being used to store the entities. 
     // you can now swap out the vector for most standard containers without 
     // changing any code other than the using and the declaration of m_entities 
     using iterator = std::vector<Entity>::iterator; 

     EntityManager(): m_entities({"bob", "bill"}) 
         // just pre-loading a few test entities 
     { 
      // RAII says you should load the entities from their source here 
     } 
     // get the first entity. 
     iterator begin() 
     { 
      return m_entities.begin(); 
     } 
     // get the end of the entity list 
     iterator end() 
     { 
      return m_entities.end(); 
     } 

     // adds an entity 
     void addEntity(const Entity & entity) 
     { 
      m_entities.push_back(entity); 
     } 

     // removes an entity 
     iterator removeEntity(iterator rem) 
     { 
      return m_entities.erase(rem); 
     } 

}; 

class System 
{ 
    public: 

     // example method to show System working with EntityManager by printing all of the Entities 
     void printEntities() 
     { 
      for (EntityManager::iterator it = m_entityManager.begin(); 
       it != m_entityManager.end(); 
       ++it) 
      { 
       it->print(); 
      } 
     } 

     // example method to show System working with EntityManager by adding Entities 
     void addMoreEntities() 
     { 
      m_entityManager.addEntity(Entity("Ted \"Theodore\" Logan")); 
      m_entityManager.addEntity(Entity("Excellent!!!")); 
     } 

    private: 
     EntityManager m_entityManager ; 
}; 

// sample test 
int main() 
{ 
    System test; 

    test.printEntities(); 
    test.addMoreEntities(); 
    test.printEntities(); 

} 

ЭТО БЫЛО ХАК. ЭТО ТОЛЬКО БЫЛО ХАК.

Если вы хотите сделать EntityManager справа, см. Writing your own STL Container для получения подсказок. Если вы хотите все колокола и свистки, работа довольно сложная. В зависимости от того, как вы используете EntityManager и сложности логики управления Entity, вам может быть лучше отказаться от EntityManager и просто использовать простой, старый std::vector.

Добавление: What is meant by Resource Acquisition is Initialization (RAII)?

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