Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > c++ static-init-fiasco


Автор: amnesiacorg 3.9.2012, 14:53
Добрый день.

Изучаю С++ по книге Bruce Eckel "Thinking in C++". В десятой главе  (Name Control) есть упражнение под номером 32:

Код

In a header file, create a class Mirror that contains two
data members: a pointer to a Mirror object and a bool.
Give it two constructors: the default constructor
initializes the bool to true and the Mirror pointer to zero.
The second constructor takes as an argument a pointer to
a Mirror object, which it assigns to the object’s internal
pointer; it sets the bool to false. Add a member function
test( ): if the object’s pointer is nonzero, it returns the
value of test( ) called through the pointer. If the pointer is
zero, it returns the bool. Now create five cpp files, each
of which includes the Mirror header. The first cpp file
defines a global Mirror object using the default
constructor. The second file declares the object in the first
file as extern, and defines a global Mirror object using
the second constructor, with a pointer to the first object.
Keep doing this until you reach the last file, which will
also contain a global object definition. In that file, main( )
should call the test( ) function and report the result. If the
result is true, find out how to change the linking order
for your linker and change it until the result is false.


Вот код:
mirror.h:
Код

#ifndef MIRROR_H_
#define MIRROR_H_

class Mirror {
 public:
  Mirror() {logic_ = true; self_ = 0;};
  Mirror(Mirror *ptr) {self_ = ptr; logic_ = false;};
  bool test() {
    if (self_ != 0) {
      return self_->test();
    } else {
      return logic_;
    }
  };

 private:
  bool logic_;
  Mirror *self_;
};


#endif // MIRROR_H_


one.cc:
Код


#include "mirror.h"

Mirror m1;


two.cc
Код

#include "mirror.h"

extern Mirror m1;
Mirror m2(&m1);



three.cc
Код

#include "mirror.h"

extern Mirror m2;
Mirror m3(&m2);


и так далее, наконец five.cc:
Код

#include "mirror.h"

#include <iostream>

extern Mirror m4;
Mirror m5 (&m4);

int main(int argc, char* argv[]) {
    std::cout << m5.test() << std::endl;
}



Однако как бы я не менял порядок линковки, m5.test() все время возвращает true.
(Порядок линковки файлов менял так: g++ five.o four.o three.o two.o one.o; Плюс пробовал указывать порядок инициализации
с помощью  __attribute__ ((init_priority (N)));)
Однако никак не получилось заставить m5.test() вернуть false.
Более того, я не совсем понимаю как этого можно добиться.
Порядок инициализации глобальных переменных в разных единацах трансляции не определен (стандартом не определяется, в каком порядке она будет выполняться, т.е. будет one.cc раньше или позже two.cc). Однако точно говорится, что к моменту вызова main() инициализация всех глобальных обьектов будет закончена. Как в этом случае можно получить проблему static-init-fiasco, если мы не зависим от внутреннего состояния обьектов в момент их инициализации (нам необходимо только адрес этих переменных, а не их состояние)?




Автор: bsa 3.9.2012, 15:51
Проблему можно получить тогда, когда один из конструкторов статических объектов пытается получить доступ к данным другого статического объекта. Обычно, данная проблема оканчивается крахом приложения еще до входа в main(). smile

Автор: amnesiacorg 3.9.2012, 16:00
Т.е. можно считать что задача сформулирована не правильно, потому что порядок линковки в данном случае никак не будет влиять на результат Mirror::test() для обьекта m5?

Автор: bsa 3.9.2012, 17:22
amnesiacorg, да.

Автор: amnesiacorg 3.9.2012, 17:30
Спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)