Проблема с инициализацией статического std :: vector <class>в том же конструкторе класса - PullRequest
1 голос
/ 28 мая 2011

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

Образец один :

#include "stdafx.h"
#include <vector>    
class A{
private:
    int aValue;
public:
    static std::vector<A*> listOfA;

    A(int i)
    {
        aValue = i;
        A::listOfA.push_back(this); // !!! HERE crash in release mode only, in debug mode items add to vector, but remove when vector initialize
    }
};

A testA(1);
std::vector<A*> A::listOfA;



int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

Образец два :

classA.h

#include <vector>

class A{
private:
    int aValue;
public:
    static std::vector<A*> listOfA;

    A(int i);
};

classA.cpp

#include "stdafx.h"
#include "classA.h"

std::vector<A*> A::listOfA;

A::A(int i)
{
  aValue = i;
  A::listOfA.push_back(this); // !!! HERE crash in release mode only, in debug mode items add to vector, but remove when vector initialize
}

main.cpp

#include "stdafx.h"
#include "classA.h"

A testA(1);

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

В примере 2, если файлы cpp в проекте имеют такой порядок (порядок компиляции), все работает нормально: classA.cpp main.cpp

Если заказать это, у нас будет сбой: main.cpp classA.cpp

Ответы [ 2 ]

0 голосов
/ 03 августа 2011

цитата из: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 Существует много решений этой проблемы, но очень простое и полностью переносимое решение состоит в замене глобального объекта listOfA глобальной функцией listOfA (), которая возвращает объектссылка.

std::vector<A*>& listOfA()
{
    static std::vector<A*> ans;
    return ans;
}

Поскольку статические локальные объекты создаются, когда первый раз управление переходит над их объявлением (только), вышеупомянутая новая инструкция listOfA () будет происходить только один раз: первый раз вызывается listOfA ().Каждый последующий вызов вернет один и тот же объект.Затем все, что вам нужно сделать, это изменить использование listOfA на listOfA ():

int _tmain(int argc, _TCHAR* argv[])
{
    // do stuff
    A::listOfA().dostuff();
    // do stuff
}

Это называется идиомой Construct On First Use, потому что он делает именно это: глобальный объект Fred создается при его первом использовании.

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

[Редактировать] Извините, не видел, что вы уже связалиськ часто задаваемым вопросамОн заслуживает похвалы [/ Edit]

0 голосов
/ 28 мая 2011

Статики инициализируются в порядке их появления в файле, поэтому, когда вы говорите:

A testA(1);
std::vector<A*> A::listOfA;

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

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

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