2016-03-21 3 views
1

у меня есть вектор и объект, объявленный в plane.h:станд :: вектор, не сохраняя сдвинуться назад объекты инстанцированы в реализации

extern Plane Default; 
extern std::vector<Plane *>universe; 

Они определены в plane.cpp:

Plane Default("Default"); 
std::vector<Plane *>universe; 

Plane конструктор:

Plane::Plane(const std::string &label) { 
    /* check universe to ensure uniqueness */ 
    std::cout << this << std:endl; //DEBUG CHECK to see what I push_back 

    universe.push_back(this); //ACTION to keep track of the planes 

    std::cout << universe.back() << std::endl; //DEBUG CHECK to ensure that it was stored correctly 
} 

выход подтверждает, что самолет действительно находится в векторе.

В главном:

if(universe.empty()) cout << "EMPTY UNIVERSE" << endl; 

показывает, что вектор не сохраняет значение. Я ожидал, что значение Default (как определено в plane.cpp) будет сохранено в юниверсе.

Demo

Однако Вселенная сохраняет значения, когда я инстанцирую самолеты из главного

Я предполагаю, что это имеет отношение к локальной копии, объем и передачи по значению, но не могу выяснить способ чтобы создать экземпляр плоскости по умолчанию INSIDE, чтобы ее адрес сохранялся в векторе.

Я также попытался объявить вектор от кучи, так как:

extern std::vector<Plane *> *universe; 

и определяется следующим образом:

std::vector<Plane *> *universe = new std::vector<Plane *>; 

Это просто разбило программу. Я использую Mingw32 4.9 на 64-битной Vista, машины в коде: Блоки 16,01 и -std = C++ 11

+4

Вы можете сварить все это в [mcve]? – NathanOliver

+1

глобальный порядок инициализации fiasco ... – Jarod42

+0

Мое предположение: вы передали значение 'universe' по значению, поместили' Plane' в копию, уничтожили копию и затем проверили оригинал, если он содержит «Plane», , Но, не видя кода, это просто спекуляция. – nwp

ответ

5

Вы попали в глобальный облом порядок инициализации:

Plane Default("Default"); 
std::vector<Plane *>universe; 

Default имеет зависимость от universe, но когда строительство Default, universe еще не построено.

Вот почему вы должны избегать глобального в целом.

обходным в вашем случае было бы изменить порядок, предполагая, есть в то же ЕП:

std::vector<Plane *>universe; 
Plane Default("Default"); 
+0

Я только что подтвердил, что это действительно устраняет проблему: http://coliru.stacked-crooked.com/a/ba1d03cb9f19b380. –

+0

Nitpick: TTBOMK Фиаско статического инициализационного процесса возникает, когда у вас есть статические переменные в * разных * исходных файлах - поскольку независимо от того, работает ли программа правильно, зависит от того, какой процесс компоновщик обрабатывает, IOW, он (вообще) даже не под контроль программиста! Здесь, хотя это, конечно, дерьмо, что программа компилируется без предупреждений и дает неправильное поведение, программист может по крайней мере гарантировать правильное поведение программы, правильно определяя порядок определений. –

+0

Это действительно было проблемой. Ваше решение работало как шарм! Большое спасибо за полезный ответ. –

0

Если у вас возникли проблемы со сферой ваших указателей, возможно, с помощью shared_ptr будет достаточно? Однако я не знаю вашего общего дизайна, если вас беспокоит постоянство указателей, которые могут быть удалены или перемещены и по-прежнему нуждаются в данных; умным указателем может быть ответ. Если есть проблема с циклами в любом месте, используйте weak_ptr, чтобы сломать его.

Удачи вам!

+0

Это звучит как расширенный комментарий, а не ответ. –

+0

Да, у меня недостаточно комментариев для комментария, видимо ... так что было бы целесообразно добавить какие-либо советы в качестве ответа. – rtbaldwin

+0

На самом деле проблема была, как правильно указал @ Jarod42 и R Sahu, порядок инициализации. Изменение порядка решило проблему, и добавление инициализатора еще больше улучшило ее. Но, как отмечалось ранее, я довольно новичок в программировании. Я собираюсь изучить shared_ptr и умные указатели. Спасибо за реплику. –

1

answer by Jarod42 должен решить возникшую проблему. Я собираюсь предложить некоторые рекомендации по предотвращению таких проблем.

В общем, лучше избегать глобальных данных, доступных с помощью объявленной переменной extern. Лучше обеспечить доступ к глобальным данным с помощью функционального интерфейса.

Вы можете изменить

extern std::vector<Plane *>universe; 

к

extern std::vector<Plane *>& getUniverse(); 

и реализовать его как:

extern std::vector<Plane *>& getUniverse() 
{ 
    static std::vector<Plane *>universe; 
    return universe; 
} 

С, что на месте, вы можете изменить конструктор Plane к:

Plane::Plane(const std::string &label) { 
    getUniverse().push_back(this); 
} 

Это устранит проблемы, связанные с порядком инициализации глобальных данных.

Вы также можете изменить

extern Plane Default; 

к

extern Plane& getDefaultPlane(); 

и реализовать его как

extern Plane& getDefaultPlane() 
{ 
    static Plane Default("Default"); 
    return Default; 
} 

Если по умолчанию Plane должны быть построены во время инициализации, вы можете использовать что-то вдоль линии:

// Use a helper struct in an anonymous namespace to initialize 
// whatever needs to be initialized. 
namespace 
{ 
    struct Initializer 
    { 
     Initializer(); 
    }; 
} 

// Make sure that Initializer::Initializer() gets called 
// at initialization time. 
static Initializer initer; 

Initializer::Initializer() 
{ 
    // Trigger construction of the default Plane 
    getDefaultPlane(); 
} 
+0

Хороший совет, но проблема OP не связана с несколькими единицами перевода, поэтому часть видимости внешнего вида здесь не имеет отношения. Также я не видел подхода в вашем последнем разделе («Если по умолчанию« Plane »...) раньше, и мне интересно, что он достигает, как в общем, так и в случае с единичным переводом. –

+0

@j_random_hacker , он предоставляет вам метод принудительной инициализации объектов во время запуска с большей степенью контроля над порядком инициализации, чем это можно было бы сделать с использованием глобальных данных. –

+0

Как интересно! Я довольно новичок в C++ (и вообще программировании). Мне нравится слой абстракции, который добавляет ваше решение. Я только что осуществил свой путь. –

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

  • Нет связанных вопросов^_^