Как получить глобальный var, который будет создан как самое первое, что есть в C ++ под win32? - PullRequest
4 голосов
/ 16 июля 2011

s Я нахожусь на Windows, и я строю проект C ++ с VS2008.Я пытаюсь заменить новый / delete / malloc / free и т. Д., Который работает, т.е. мои замены вызывают.

Однако мой замещающий распределитель должен быть инициализирован.До сих пор я делал это, определяя его как глобальную переменную в файле .cpp с определенной в нем #pragma init_seg (lib).

Это работало до недавнего времени, когда начал инициализироваться std :: locale, который вызывал new до инициализации моего распределителя.Поэтому я нервно переместил глобальную переменную моего распределителя в сегмент компилятора, т.е. #pragma init_seg (compiler).

Это немного подействовало, и затем я решил переопределить malloc.Теперь я получаю вызов malloc в __crtGetStringTypeA_stat в _tmainCRTStartup, который происходит до того, как инициализируются даже глобальные переменные в сегменте компилятора.

Есть ли какой-либо способ создания моей переменной до запуска CRT.Единственное, о чем я могу подумать, это перестроить мою библиотеку crt и попробовать кое-что, как вставить мой код инициализации туда-сюда.Я предполагаю, что должна быть также функция очистки crt?

Есть ли более простой путь к этому и / или что-то очевидное, что я здесь упускаю?

Ответы [ 2 ]

5 голосов
/ 17 июля 2011

Вы используете static storage duration объект.

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

MyAllocator& getAllocator()
{
    static  MyAllocator  allocator;  // Note the static here.
                                     // It has the appropriate lifespan and will be destoryed.
                                     // and is automatically constructed the first time this
                                     // function is called.
    return allocator;
}

Теперь ваши версии new / delete / etc могут получить ссылку на распределитель, вызвав getAllocator (). Это гарантирует, что объект правильно инициализирован (при условии, что MyAllocator имеет правильный конструктор).

1 голос
/ 17 июля 2011

В Windows вы можете использовать InitOnceExecuteOnce для инициализации вашего распределителя.Например:

static INIT_ONCE initFlag = INIT_ONCE_STATIC_INIT;

static BOOL CALLBACK InitMyHeap(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
    *Context = (PVOID)CreateMyHeap();
}

MyHeap *GetMyHeap()
{
    PVOID vpMyHeap;
    if (!InitOnceExecuteOnce(&initFlag, InitMyHeap, NULL, *vpMyHeap)) {
        abort();
    }
    return (MyHeap *)vpMyHeap;
}

При этом ваша куча будет инициализирована ровно один раз, после вызова GetMyHeap().Затем ваши переопределения new / delete / malloc должны вызвать GetMyHeap(), чтобы получить указатель на структуру кучи (или просто убедиться, что куча инициализирована).Это безопасно даже для нескольких потоков, и даже если это происходит до инициализации CRT, поскольку initFlag является статическими данными в вашем сегменте данных и не требует вызова конструктора.1013 * должен быть осторожен, чтобы не использовать услуги ЭЛТ;напрямую вызывать только функции Windows DLL (например, kernel32.dll и друзья).

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