2016-02-25 6 views
-1

Я использую logger, который сохраняет print args в кортеж. кортеж используется в потоке журнала.std :: tuple args жизненный цикл?

class LogTransaction 
{ 
public: 
    typedef std::unique_ptr<LogTransaction> Ptr; 

    LogTransaction() {} 
    virtual ~LogTransaction() {} 

    virtual void Log(std::FILE* file) = 0; 
}; 

template<typename... Ts> 
class LogTransaction : public LogTransaction 
{ 
public: 

    template<typename... Args> 
    LogTransaction(Args&&... args) : m_args(std::forward<Args>(args)...) {} 

    ~LogTransaction() 
    { 
     if (m_trd.joinable()) 
     { 
      m_thrd.join(); 
     } 
    } 

    virtual void Log(std::FILE* file) override 
    { 
     Log(file, m_args); 
    } 

private: 

    template <class T> T convert(const T& val) { return val; } 
    const char* convert(const std::string& val) { return val.c_str(); } 

    // Sequence generator 
    template <std::size_t... Idx> 
    struct index {}; 

    template <std::size_t N, std::size_t... Idx> 
    struct gen_seq : gen_seq<N - 1, N - 1, Idx...> {}; 

    template <std::size_t... Idx> 
    struct gen_seq<0, Idx...> : index<Idx...> {}; 

    template <typename... Args> 
    void Log(std::FILE* file, std::tuple<Args...>& tup) 
    { 
     Log(file, tup, gen_seq<sizeof...(Args)>{}); 
    } 

    template <typename... Args, std::size_t... Is> 
    void Log(std::FILE* file, std::tuple<Args...>& tup, index<Is...>) 
    { 
     fprintf(file, convert(std::get<Is>(tup))...); 
    } 
private: 
    std::tuple<Ts...> m_args; 
}; 

class Logger 
{ 
public: 
    Logger(); 
    ~Logger(); 

    bool Start (const std::string& fileName) 
    { 
     m_file = std::fopen(fileName.c_str(), "a"); 
     if (!m_file) 
     { 
      return false; 
     } 

     m_run.store(true); 
     m_thrd = std::move(std::thread([this]{ Run(); })); 
     return true; 
    } 

    void Stop() 
    { 
     m_run.store(false); 
    } 

    template<typename... Args> 
    inline void Log (Args&&... args) 
    { 
     m_queue.push(CreateTransaction(std::forward<Args>(args)...)); 
    } 

private: 
    void Run() 
    { 
     while(m_run) 
     { 
      std::list<LogTransaction::Ptr> transactions = m_queue.pop_all(); 
      for (const auto& pTransaction : transactions) 
      { 
       pTransaction->Log(m_file); 

       fprintf(file, "\n"); 
       fflush(file); 
      } 
     } 

     std::fclose(m_file); 
    } 

    template<typename... Args> 
    inline LogTransaction::Ptr CreateTransaction (Args&&... args) 
    { 
     LogStringTransaction<Args...>* pLogTransaction = new LogStringTransaction<Args...>(std::forward<Args>(args)...); 
     return std::move(LogTransaction::Ptr(pLogTransaction)); 
    } 

private: 
    std::thread m_thrd; 

    std::FILE* m_file; 
    std::atomic_bool m_run; 
    lockfree_queue<LogTransaction::Ptr> m_queue; 
}; 

использование:

Logger logger(); 
Logger.start("test.log"); 

Logger.Log(....); 

Регистратор постоянно врезаться. Вот свалка:

#2 0x0000000000497c63 in Log<char const (&) [57], std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, 0ul, 1ul, 2ul> (tup=..., file=0x1d00400, this=<optimized out>) at ./algo/orderd/../algoutil/include/algoutil/logger.hpp:122 
#3 Log<char const (&) [57], std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&> (tup=..., file=0x1d00400, this=<optimized out>) at ./algo/orderd/../algoutil/include/algoutil/logger.hpp:116 
#4 tt::algoutil::LogStringTransaction<char const (&) [57], std::string&, std::string const&>::Log (this=<optimized out>, file=0x1d00400) 
at ./algo/orderd/../algoutil/include/algoutil/logger.hpp:95 

в соответствии с дампом. std :: tuple ссылается на некоторые аргументы, потому что аргумент arg равен lvalue. Когда аргумент выходит за пределы области действия, Logger выйдет из строя, потому что он использует объект мусора.

Как сделать копию всех элементов кортежа?

+0

Просьба указать [минимальный, полный и проверяемый пример] (http://www.stackoverflow.com/help/mcve). Я предполагаю, что вы держите ссылки на временные. – Barry

+0

@Barry Я обновил код. Точно, кортеж содержит ссылку, если lvalue передано в функцию Log(). Мой вопрос: как мне сделать копию? – kzhdev

ответ

2

Код не компилируется: класс принимает Ts..., но кортеж использует Args.... Пожалуйста, в будущих сообщениях MCVE.

Возможно, вы храните tuple<Args...>, где Args... выведено ссылочным способом пересылки как Args&&.... В этом случае пул типов Args... может содержать ссылочные типы.

Чтобы исправить это, измените тип кортежа на std::tuple<std::decay_t<Args>...>, что делает типы подходящими для хранения.

Обратите внимание, что если вы пройдете массивы необработанных символов с недостаточным сроком службы, это все равно не удастся.

+0

std :: tuple ...> сделал трюк. Я попробовал std :: decay раньше, когда создавал экземпляр кортежа в списке инициализации, но получал ошибки компиляции. Во всяком случае, он работает сейчас. Благодарю. – kzhdev