Частично инициализировать переменную, определенную в другом модуле - PullRequest
3 голосов
/ 06 июля 2010

Я рассматриваю определенное решение, в котором я хотел бы инициализировать ячейку массива, которая определена в другом модуле (будет много модулей, инициализирующих одну таблицу).Массив не будет прочитан до запуска main (поэтому нет проблем со статическим порядком инициализации).

Мой подход:

/* secondary module */

 extern int i[10]; // the array

 const struct Initialize {
  Initialize() { i[0] = 12345; }
 } init;


/* main module */

 #include <stdio.h>


 int i[10];

 int main()
 {
  printf("%d\n", i[0]); // check if the value is initialized
 }

Компилятор не будет исключать init константу, потому что конструктор имеет побочные эффекты.Я прав?Механизм в порядке?На GCC (-O3) все нормально.

// EDIT
В реальном мире будет много модулей. Я хочу избежать дополнительного модуля, центрального места, в котором будут собраны все второстепенные процедуры инициализации (для лучшей масштабируемости).Поэтому важно, чтобы каждый модуль запускал свою собственную инициализацию.

Ответы [ 5 ]

3 голосов
/ 06 июля 2010

Это работает с компиляторами MSVC, но с GNU C ++ - нет (по крайней мере, для меня).GNU linker удалит все символы, не используемые за пределами вашего модуля компиляции.Я знаю только один способ гарантировать такую ​​инициализацию - идиома "init Once".Например:

init_once.h:

template <typename T>
class InitOnce
{
    T *instance;
    static unsigned refs;
public:
    InitOnce() {
        if (!refs++) {
            instance = new T();
        }
    }

    ~InitOnce() {
        if (!--refs) {
            delete instance;
        }
    }
};
template <typename T> unsigned InitOnce<T>::refs(0);

unit.h:

#include "init_once.h"

class Init : public InitOnce<Init>
{
public:
    Init();
    ~Init();
};
static Init module_init_;

second.cpp:

 #include "unit.h"
 extern int i[10]; // the array

 Init::Init()
 {
     i[0] = 12345;
 }
 ...
0 голосов
/ 06 июля 2010

Могу я спросить, почему вы используете массив (риск выхода за пределы), когда вы можете использовать std::vector?

std::vector<int>& globalArray()
{
  static std::vector<int> V;
  return V;
}

bool const push_back(std::vector<int>& vec, int v)
{
  vec.push_back(v);
  return true; // dummy return for static init
}

Этот массив лениво инициализируется при первом вызовеfunction.

Вы можете использовать его примерно так:

// module1.cpp
static bool const dummy = push_back(globalArray(), 1);

// module2.cpp
static bool const dummy = push_back(globalArray(), 2);

Кажется, это намного проще и менее подвержено ошибкам.Это не совместимо с многопоточностью до C ++ 0x.

0 голосов
/ 06 июля 2010

Я не думаю, что вам нужен extern int i[10]; в вашем основном модуле, adf88.

0 голосов
/ 06 июля 2010

Это может сработать, но это опасно.Порядок построения глобальных / статических элементов в одном модуле не определен, как и порядок загрузки модулей (если вы не управляете им явно).Например, вы предполагаете, что во время выполнения ctor в initial.c Initialize () i уже присутствует.Вы должны быть очень осторожны, чтобы два модуля не инициализировали одни и те же общие данные, или чтобы два модуля выполняли инициализацию с перекрывающимися побочными эффектами.

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

/ основной модуль (main.c) /

# включает класс CommonDat {int i;

public:
    const int GetI()    { return i;}
    void SetI(int newI) { i = newI; }
    void incI()         
     {
      AcquireSomeLock();
      i++;
      ReleaseTheLock();
     }
}

CommonDat g_CommonDat;
CommonDat*  getCommonDat()   { return &g_CommonDat; }

int main(void)
{
     printf("%d",getCommonDat()->GetI()); 
}

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

(ПРИМЕЧАНИЕ: выназвал файлы как файлы C, но отметил вопрос как c ++. Предлагаемый код, конечно, c ++).

0 голосов
/ 06 июля 2010

EDIT

 /*secondary module (secondary.cpp) */

  int i[10]; 
  void func()
  {
       i[0]=1;

  }

.

 /*main module (main.cpp)*/

  #include<iostream>

  extern int i[];
  void func();
  int main()
  {
     func();
     std::cout<<i[0]; //prints 1
  }

Компилировать, связывать, создавать и выполнять, используя g++ secondary.cpp main.cpp -o myfile

Как правило, конструкторы используются (и должны использоваться) только для инициализации членов класса.

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