static members.
От: Mechanicus Беларусь  
Дата: 05.02.04 14:11
Оценка:
Вот натолкнулся на такую проблему с использованием субжа. Есть два модуля
module.cpp
#include "module.h"

#include <exception>
#include <iostream>
#include <boost/bind.hpp>

Module::worldFactory_t Module::worldFactory_;

bool Module::init()
{
    getWorld();

    return true;
}

int main()
{
    try {
        Module::create()->init();
    }
    catch (std::exception &ex) {
        std::cout << ex.what() << std::endl;
    }
    std::cout << "done." << std::endl;
    return 0;
}

module.h
#ifndef MODULE_H
#define MODULE_H

#include <boost/function.hpp>
#include <boost/utility.hpp>
#include <iostream>

    class World;
    class Module
    {
    public:
        static bool registerWorld(World *(*createFn)())
        {
            std::cout << "World is registered." << std::endl;
            worldFactory_ = createFn;
            return true;
        }
        World *getWorld()
        {
            return worldFactory_();
        }

        static Module *create() 
        {
            static Module obj_;
            return &obj_;
        }
        bool init();

    private:
        typedef boost::function0<World *> worldFactory_t;
        static worldFactory_t worldFactory_;
    };

#endif


и

world.cpp
#include "module.h"
#include "world.h"

namespace 
{
    World *create()
    {
        static World obj;
        return &obj;
    }

    static bool world_registered = 
        Module::registerWorld(create);
}


world.h
#ifndef AAA
#define AAA

#include <boost/utility.hpp>

class World : boost::noncopyable
{
};

#endif //AAA


При компиляции с помощю mingw(gcc-3.3.1) и выполнении этой программы стабильно на cout выдаётся
World is registered.
call to empty boost::function
done.
VC7.0 всё компилит и выполняет нормально. Я даже не знаю кто тут прав, вроде код верный, и VC прав, хотя кто его знает.
... << RSDN@Home 1.1.3 beta 1 >>
Re: static members.
От: Павел Кузнецов  
Дата: 05.02.04 15:37
Оценка: 3 (1) +1
Здравствуйте, Mechanicus, Вы писали:

M> module.cpp

M>
 M> . . .
 M> Module::worldFactory_t Module::worldFactory_;
 M> . . .
 M>


M> module.h

M>
 M> . . .
 M>  class Module
 M>  {
 M>  public:
 M>   static bool registerWorld(World *(*createFn)())
 M>   {
 M>    std::cout << "World is registered." << std::endl;
 M>    worldFactory_ = createFn;
 M>    return true;
 M>   }
 M>   . . .
 M>


M> world.cpp

M>
 M> . . .
 M>  static bool world_registered = Module::registerWorld(create);
 M> . . .
 M>


M> При компиляции с помощю mingw(gcc-3.3.1) и выполнении

M> этой программы стабильно на cout выдаётся World is registered.
M> call to empty boost::function
M> done.

Подозреваю, что сначала вызывается registerWorld, а затем — конструктор
boost::function для объекта Module::worldFactory_, что приводит к обнулению
указателя, в нем содержащегося.

M> VC7.0 всё компилит и выполняет нормально. Я даже не знаю кто тут прав, вроде

M> код верный, и VC прав, хотя кто его знает.

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

Для решения можно, например, заменить статическую переменную-член worldFactory_
на статическую функцию вида:
/* static */
Module::worldFactory_t& Module::worldFactory_()
{
  static Module::worldFactory_t theFactory;
  return theFactory;
}
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: static members.
От: Mechanicus Беларусь  
Дата: 05.02.04 15:51
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Подозреваю, что сначала вызывается registerWorld, а затем — конструктор

ПК>boost::function для объекта Module::worldFactory_, что приводит к обнулению
ПК>указателя, в нем содержащегося.
Блин. Точно. Я знал что function где-то обнуляется, но никак не мог понять где.

M>> VC7.0 всё компилит и выполняет нормально. Я даже не знаю кто тут прав, вроде

M>> код верный, и VC прав, хотя кто его знает.

ПК>Оба правы: стандарт не гарантирует порядок инициализации глобальных объектов в

ПК>разных единицах трансляции.
Кстати есть ещё такое момент. Можно ли писать так?
1.cpp
namespace {
    bool reg = ....;
}
2.cpp
namespace {
    bool reg = ....;
}

VC7.0 при линковке ругается на то, что reg уже определён в другом модуле. Разве он прав
... << RSDN@Home 1.1.3 beta 1 >>
Re[3]: static members.
От: Павел Кузнецов  
Дата: 05.02.04 15:58
Оценка:
Здравствуйте, Mechanicus, Вы писали:

M> Можно ли писать так?

M>
 M> 1.cpp
 M> namespace {
 M>  bool reg = ....;
 M> }
 M> 2.cpp
 M> namespace {
 M>  bool reg = ....;
 M> }
 M>


Можно.

M> VC7.0 при линковке ругается на то, что reg уже определён в другом модуле.

M> Разве он прав

Неправ. Ты уверен, что код привел точно?
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: static members.
От: Mechanicus Беларусь  
Дата: 05.02.04 16:48
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

M>> Можно ли писать так?

M>>
 M>> 1.cpp
 M>> namespace {
 M>>  bool reg = ....;
 M>> }
 M>> 2.cpp
 M>> namespace {
 M>>  bool reg = ....;
 M>> }
 M>>

ПК>Можно.
M>> VC7.0 при линковке ругается на то, что reg уже определён в другом модуле.
M>> Разве он прав
ПК>Неправ. Ты уверен, что код привел точно?
Дело в том, что прям так выделить его в два файла у меня не получилось. У меня в файлах примерно такой код регистрации.
namespace {
    bool registered = 
        startup::ModuleLibrary::instance()->registerModule(
            cfg::Module::create()
            );
};

В различных файлах меняется либо пространстов имён cfg на другое, либо совсем другие функции регистрации вызываются, но линкер железно выдаёт.

error LNK2005: "bool `anonymous namespace'::registered" (?registered@?A0xbb0ee478@@3_NA) already defined in module3.obj

gcc всё компилирует и линкует нормально.
... << RSDN@Home 1.1.3 beta 1 >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.