2015-04-11 3 views
0

Я пытаюсь написать класс журнала с практикой threadsafe в C++. Теперь дело в том, что я хочу сделать вызов для каждой строки журнала очень простым. Я могу пойти со статическим способом класса, как показано ниже:C++ singleton класс экземпляр доступ ко всему приложению

//Calling this in some GUI initialization point of application 
CLogger::InitLogger("LogFile.log"); 

//Calling below from any class just adding the header to the cpp 
CLogger::Log("Some informational text goes here"); 

Теперь это не следует ООП так хотелось пойти с классом одноэлементных.

//Singleton log class 
class CLogWrite 
{ 
public: 
    static CLogWrite* GetInstance(); 

private: 
    static CLogWrite *pInstance; 
    void Log(); 
}; 

CLogWrite* CLogWrite::GetInstance() 
{ 
    if(pInstance != NULL) 
    { 
    pInstance = new CLogWrite; 
    } 
    return pInstance; 
} 

void CLogWrite::Log() 
{ 
    //threadSafe lock 

    //write 'logText' to file here 

    //threadSafe unlock 
} 

Теперь дело в том, если я пишу выше класса и вызвать CLogWriter :: GetInstance() внутри моего GUI функции класса инициализации, как показано ниже:

//single logger instance for my app 
CLogWriter *mLogInstance; 
mLogInstance = CLogWriter::GetInstance() 

Мне нужно передать переменную «mLogInstance» в каждый класс внутри моего проекта, откуда я хочу написать журнал. Но я не хочу этого делать.

Что было бы лучше всего подходит?

+0

Почему вы не можете объявить глобальную переменную, потому что в нашем приложении мы использовали глобальную переменную –

+0

«переменная для каждого класса». что это значит. –

+2

Зачем изобретать колесо? Вы можете использовать существующую библиотеку ведения журнала, такую ​​как [Boost.log] (http://www.boost.org/libs/log/doc/html/index.html) или [glog] (https://github.com/google/GLog). –

ответ

2

Попробуйте это:

class Singleton 
{ 
public: 
    static Singleton& getInstance() 
    { 
     static Singleton instance; 
     return instance; 
    } 

    Singleton(Singleton const&) = delete; 
    void operator=(Singleton const&) = delete; 

private: 
    Singleton() {};   
}; 
+0

Не могли бы вы объяснить это. –

+0

Не могли бы вы немного объяснить. – hypheni

+0

@PLearner Это хорошо известно как [SingleStyle idiom__Scott Meyer] (http://stackoverflow.com/questions/25173716/player-obj-error-lnk2001-unresolved-external-symbol-private-static-class-in/25173785? s = 2 | 0.3768 # 25173785) –

1

Один из моих любимых методов в C++ так называемые CRTP, которые могут быть использованы для реализации одноплодной логики. Посмотрите на этот код:

template <class Type> 
class Singleton 
{ 
private: 
    static std::unique_ptr<Type> _holder_ptr; 
    static std::mutex    _mutex; 

public: 
    static Type& GetSingleton() 
    { 
     if(!_holder_ptr) 
      _create_instance(); 

     return *(_holder_ptr.get()); 
    } 

protected: 
    static void _create_instance() 
    { 
     _mutex.lock(); 

     if(!_holder_ptr) 
      _holder_ptr.reset(new Type()); 

     _mutex.unlock(); 
    } 
}; 

Теперь вы можете использовать этот класс, чтобы определить "одиночек":

class Log : public Singleton<Log> 
{ 
    //content 
}; 

и использовать его:

Log& global_log = Log::GetSingleton(); 
//do something 

Это версия для C++ 11. Для старых компиляторов замените std::mutex на платформозависимый синхронизирующий примитив. В Windows вы можете использовать CRITICAL_SECTION. Пример использования: here.

std::unique_ptr также был введен в C++ 11, так что вы можете либо заменить его std::auto_ptr (устаревшее в C++ 11), используйте smart pointer from Boost library или создать собственное решение (которое не трудно, но изобретать велосипед не очень хорошая идея) ,

Обратите внимание, что это Singleton не запрещает создавать дополнительные экземпляры Log - и это не должно! Есть два основных сценария:

  • Вы позволяют пользователям создавать дополнительные экземпляры Log, но в то же время спрос, что по крайней мере один такой объект должен существовать. Тогда простое из Singleton - это все, что вам нужно.
  • Для этого нужно указать Log «Singleton», то есть может существовать только один, общий экземпляр - остальная часть кода должна использовать этот экземпляр, поэтому все может работать так, как ожидалось. В этом случае используйте синтаксис = delete, чтобы удалить конструктор по умолчанию, конструктор копирования и оператор присваивания (или просто объявить их как protected или private, в зависимости от поддержки компилятора для синтаксиса = delete).

Кроме того, помните, что если вы хотите использовать общий экземпляр в качестве указателя, вам нужно использовать какие-то умные указатели, как показано выше.Вы не можете использовать простые указатели, как в исходном растворе:

CLogWrite* CLogWrite::GetInstance() 
{ 
    if(pInstance != NULL) 
    { 
     pInstance = new CLogWrite; 
    } 
    return pInstance; 
} 

Где и когда pInstance будет уничтожен? Как?

+0

Спасибо за аккуратный код и его объяснение. Теперь переходим к 'Log & global_log = Log :: GetSingleton();' - эта вещь должна быть членом класса или глобальной переменной. Не так ли? – hypheni

+0

Что значит? Все, что вам нужно сделать, это вызвать 'GetSingleton()' каждый раз, когда вам нужно получить глобальный экземпляр класса singleton. –

+0

О да. Я понял. – hypheni

Смежные вопросы