15

Я использую C++ в Visual Studio 2015 sp3. ПоМогу ли я изменить статический порядок инициализации переменных в C++?

#pragma init_seg(compiler) 

, я инициализировать некоторые статические переменные первого (для управления памятью). https://msdn.microsoft.com/en-us/library/7977wcck.aspx

Но есть

#pragma init_seg(compiler) 

в wcerr.cpp (Microsoft Visual Studio 14.0 \ VC \ элт \ SRC \ СТЛ \ wcerr.cpp), так что эти объекты инициализируются перед тем мои объекты.

Могу ли я принудительно инициализировать мой объект перед wcerr.cpp объектами по любым параметрам компиляции/ссылки?

+0

Почему заказ имеет значение? –

+0

@ Cheersandhth.-Alf Поскольку мой объект инициализирует пользовательскую систему памяти, если некоторые другие объекты вызывают новое перед моим объектом, это делает ошибку. :( –

+4

Итак, фактический вопрос - [как переопределить распределитель памяти в MSVC] (http://stackoverflow.com/questions/12815867/overriding-memory-allocator-in-msvc) – rustyx

ответ

12

Одно из решений заключается в попытке обернуть ваши статические переменные статических функций:

static type& My_static_obj() { 
    static type my_static_obj_; 
    return my_static_obj_; 
} 

Это выглядит как простой тип Singleton и звонки Construct При первом использовании Idiom. Из-за стандартного (C++ 11 и выше) он гарантированно инициализируется один раз (и даже атомарно!), И внутри его c-tor такой объект может иметь доступ к другим «статическим» переменным, поэтому, если нет кругового зависимостей между переменными, порядок инициализации будет строго определен.

Дополнительную информацию см. В this question и других описаниях этого Построить при первом использовании Idiom.

+0

«Построить при первом использовании идиомы» Хорошая информация.Спасибо.Но я должен построить объект до того, как в Microsoft Visual Studio 14.0 \ VC \ crt \ src \ stl \ wcerr.cpp. Могу ли я использовать эту идиому для wcerr? –

+0

[Стандарт] (http: // en.cppreference.com/w/cpp/io/cerr) говорит, что это (_possible_) может быть достигнуто путем включения '' _after_ инициализации вашего объекта (2-й абзац, он вызывает 'std :: ios_base :: Init' [инициализация] (http://en.cppreference.com/w/cpp/io/ios_base/Init)), возможно, вам придется делать форвардные объявления для 'wcerr'. Или вы можете явно расширить' std :: ios_base :: Init' c -тор для ваших целей, но это грязный взлом, попробуйте и сообщите нам. Еще раз: в общем, как уже упоминалось, порядок не определен и кажется VS nd Win попытается инициализировать свою утилиту перед любым кодом пользователя. – Trollliar

3

Вероятно nifty counter идиома может помочь вам как-то в этом случае:

Обеспечить нелокальной статический объект инициализируется перед первым использованием и уничтожен только после последнего использования объекта.

Его мотивация очень ясна:

Когда статические объекты используют другие статические объекты, проблема инициализации становится все более сложным. Статический объект должен быть инициализирован перед его использованием, если он имеет нетривиальную инициализацию. Порядок инициализации статических объектов в единицах компиляции не определен. Несколько статических объектов, распространяемых по нескольким единицам компиляции, могут использовать один статический объект. Поэтому он должен быть инициализирован перед использованием. Одним из примеров является std :: cout, который обычно используется рядом других статических объектов.

Это стоит того, чтобы скопировать и вставить непосредственно в пример из приведенной выше связанной страницы:

Stream.h

#ifndef STREAM_H 
#define STREAM_H 

struct Stream { 
    Stream(); 
    ~Stream(); 
}; 
extern Stream& stream; // global stream object 

static struct StreamInitializer { 
    StreamInitializer(); 
    ~StreamInitializer(); 
} streamInitializer; // static initializer for every translation unit 

#endif // STREAM_H 

поток.каст

#include "Stream.h" 

#include <new>   // placement new 
#include <type_traits> // aligned_storage 

static int nifty_counter; // zero initialized at load time 
static typename std::aligned_storage<sizeof (Stream), alignof (Stream)>::type 
    stream_buf; // memory for the stream object 
Stream& stream = reinterpret_cast<Stream&> (stream_buf); 

Stream::Stream() 
{ 
    // initialize things 
} 
Stream::~Stream() 
{ 
    // clean-up 
} 

StreamInitializer::StreamInitializer() 
{ 
    if (nifty_counter++ == 0) new (&stream) Stream(); // placement new 
} 
StreamInitializer::~StreamInitializer() 
{ 
    if (--nifty_counter == 0) (&stream)->~Stream(); 
} 

Заголовочный файл класса поток должен быть включен до того, как функция-член может быть вызван на объект Stream. Экземпляр класса StreamInitializer включен в каждый блок компиляции. Любое использование объекта Stream следует за включением заголовка, который гарантирует, что конструктор объекта инициализатора вызывается перед использованием объекта Stream.

См. Ссылку выше для получения более подробной информации.

1

EDIT: Я думаю, что вам нужно использовать другую реализацию STL, если вам нужно использовать MSVC 2015, а также избегать переопределения вашего текущего ручка управления памятью (извините, что назовете это, но это то, на что это похоже, но затем снова я использовал несколько собственных хаков для работы с MSVC).

Я никогда не использовал реализацию STL, которая не была включена в среду разработки, но это возможно. Это должно быть простой вопрос - установить пути включения и библиотеки в альтернативную реализацию STL. Вы можете начать с попытками STLPort

В противном случае, мой первоначальный совет относительно вашего вопроса, до последнего редактирования:

Статический порядок инициализации в модуле компиляции (файл CPP) порядок, в котором сделаны заявления. Статический порядок инициализации между единицами компиляции не определен. Не используйте статическую инициализацию для решения этой проблемы.

Похоже, что RustyX направляет вас в правильном направлении, ссылаясь на Overriding memory allocator in MSVC++.

EDIT: похоже, ответ, который вы ищете, может быть здесь: How to properly replace global new & delete operators. Обратите внимание, что оба ответа актуальны, вы захотите заменить new, delete, new[] и delete[]. Поскольку это применяется во время связывания, очевидно, Windows не будет использовать их для загружаемых DLL (см. Комментарии к первому ответу).

+0

Потому что код управления памятью не только мой, но и в рамках. До MSVC 2015 он всегда строился до wcerr. Даже в MSVC 2015, в сборке Debug, мой статический объект построен до wcerr. Только в версии Release, порядок построения объекта изменяется. –

+0

Звучит как проблема с прямой совместимостью. Вам повезло в предыдущих версиях MSVC, я бы сказал, что не используйте MSVC 2015. Вы использовали специальную директиву компилятора, на которую не следовало полагаться по причинам, которые я изложил о статическом порядке инициализации. Компиляторы (и библиотеки) меняются. Вы только вариант для использования MSVC 2015, я думаю, не использовать STL от Microsoft, или, возможно, изменить его и построить самостоятельно (но я не думаю, что он лицензирован для этой цели). Например, Boost имеет авторитетную реализацию STL. –

0

вы можете получить идею от проекта Chromium Docs. См. Раздел «Singleton & base :: LazyInstance».