使用单一实例分配静态成员
Using a Singleton to assign a Static Member
我不想使标题过于复杂,但我设计了一些比我指出的要复杂得多的东西。至少在基本原则上,代码几乎类似于以下内容。
template<output_stream>
class logger
{
output_stream streamer
}
using xlog = logger<x>
class singleton_manager
{
static int register_log(string x)
{
logs.pushback(x related thing)
return logs.size() - 1
}
static std::ostringstream(int index)
static std::vector<xlog> logs
}
class unrelated
{
static int logindex
void error()
}
int logindex = singleton_manager::register_log("simplest_example.log")
所以问题是,当我从我的 unrelated.cpp 调用上面的行时,register_log(( 不会保留新日志。
它运行该方法..
创建新日志。.
返回新日志的索引。
将返回的值分配给静态成员。.
噗,新日志实际上并不存在。.
我唯一能理解的是,因为赋值是针对静态成员的,并且使用单例的静态方法,所以它只假装创建新日志。或者也许是因为模板?任何关于我的错误是什么的意见将不胜感激。
编辑:你要求它。
文件: s3d_mesh.h
#ifndef S3DMESH_H_
#define S3DMESH_H_
#include <vector>
#include <fstream>
#include <debug_toolset.h>
using std::vector;
using std::string;
using std::ifstream;
struct s3d_vertex
{
float array[8];
void Load(ifstream& file)
{
file >> array[0];
file >> array[1];
file >> array[2];
file >> array[3];
file >> array[4];
file >> array[5];
file >> array[6];
file >> array[7];
}
};
struct s3d_index
{
float array[3];
void Load(ifstream& file)
{
file >> array[0];
file >> array[1];
file >> array[2];
}
};
class s3d_mesh
{
private:
static int errorlog_index;
int total_indices;
int total_vertices;
string texture_file;
protected:
vector<s3d_index> Indices;
vector<s3d_vertex> Vertices;
public:
s3d_mesh(){}
s3d_mesh(string file_path);
void Load(string file_path);
};
#endif
文件: s3d_mesh.cpp
#include "s3d_mesh.h"
#include <sstream>
#include <debug_toolset.h>
using std::stringstream;
int s3d_mesh::errorlog_index = dbg::FileLog_Mgr::RegisterNewLog(L"s3d_errors.log");
s3d_mesh::s3d_mesh(string file_path)
{
Load(file_path);
}
void s3d_mesh::Load(string file_path)
{
ifstream File_Handle;
File_Handle.open(file_path, std::ios::in);
try
{
File_Handle >> total_vertices;
for ( int i = 0; i < total_vertices; ++i )
{
s3d_vertex temp;
temp.Load(File_Handle);
Vertices.push_back(temp);
}
File_Handle >> total_indices;
for ( int i = 0; i < total_indices; ++i )
{
s3d_index temp;
temp.Load(File_Handle);
Indices.push_back(temp);
}
File_Handle >> texture_file;
File_Handle >> texture_file;
File_Handle >> texture_file;
File_Handle >> texture_file;
if ( File_Handle.fail() )
throw File_Handle.rdstate();
File_Handle.close();
}
catch ( ... )
{
dbg::FileLog_Mgr::Start();
LOGFILEX(errorlog_index, dbg::logERROR) << "tS3D File - Critical Failure Loading";
dbg::FileLog_Mgr::Stop();
}
}
文件: debug_toolset.h
/*The MIT License (MIT)
Copyright (c) <2014> <Josh S, Cooper>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
#ifndef _DBG_LOG_
#define _DBG_LOG_
#include "lib_linkersdbglinker.h"
#include <assert.h>
#include <cstdio>
#include <vector>
#include <fstream>
#include <sstream>
#include <thread>
#include <functional>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#include <windows.h>
//#include <stdio.h>
/*
Function for grabbing the timestamps
Windows Version
*/
inline std::string NowTime()
{
const int MAX_LEN = 200;
char buffer[MAX_LEN];
if ( GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0,
"HH':'mm':'ss", buffer, MAX_LEN) == 0 )
return "Error in NowTime()";
char result[100] = { 0 };
//std::string result = "";
static DWORD first = GetTickCount();
/*result += buffer;
result += ".";
result += (long)first;*/
std::sprintf(result, "%s.%03ld", buffer, ((long)(GetTickCount() - first) % 1000));
return result;
}
#else
#include <sys/time.h>
inline std::string NowTime()
{
char buffer[11];
time_t t;
time(&t);
tm r = {0};
strftime(buffer, sizeof(buffer), "%X", localtime_r(&t, &r));
struct timeval tv;
gettimeofday(&tv, 0);
char result[100] = {0};
std::sprintf(result, "%s.%03ld", buffer, (long)tv.tv_usec / 1000);
return result;
}
#endif //WIN32
namespace dbg
{
//Enums representing the different log levels
// Implemented as bits in a Byte as to facilitate turning specific levels on and off with a #define macro
enum LogLevel
{
logFATAL = 1 << 0, logERROR = 1 << 1,
logWARNING = 1 << 2, logINFO = 1 << 3,
logDEBUG1 = 1 << 4, logDEBUG2 = 1 << 5,
logDEBUG3 = 1 << 6, logDEBUG4 = 1 << 7
};
//Forward declaration for friend statement
class FileLog_Mgr;
/*
Logger template class
Implemented with a built-in Object of the OutputPolicy class
Logger expects very little of this Policy class itself as its methods' only use of the
Output Object are where it is being overwritten with a new OutputPolicy object
REQUIRED are an operator= overload + copy constructor
*/
template <typename OutputPolicy>
class Logger
{
friend FileLog_Mgr;
public:
virtual ~Logger()
{
}
Logger(){}
Logger(const Logger& other)
{
Output = other.Output;
}
Logger& operator=(const Logger& other)
{
Output = other.Output;
return *this;
}
inline LogLevel& ReportingLevel()
{
static LogLevel reportingLevel = logDEBUG4;
return reportingLevel;
}
inline std::string ToString(LogLevel level)
{
switch ( level )
{
case logFATAL:
return "t~FATAL~tt";
break;
case logERROR:
return "tERROR: tt";
break;
case logWARNING:
return "WARNING: t";
break;
case logINFO:
return "INFO:t ";
break;
case logDEBUG1:
return "DEBUG1:tt";
break;
case logDEBUG2:
return "DEBUG2:tt ";
break;
case logDEBUG3:
return "DEBUG3:tt ";
break;
case logDEBUG4:
return "DEBUG4:tt ";
break;
}
}
inline std::ostringstream& Get(LogLevel level = logINFO)
{
buffer << std::endl << " - " << NowTime() << " - t";
buffer << ToString(level);
return buffer;
}
protected:
std::ostringstream buffer;
OutputPolicy Output; //templated output
};
/*
*/
class FileStream_Policy
{
public:
virtual ~FileStream_Policy()
{
if ( file_stream.is_open() )
{
file_stream.close();
}
}
FileStream_Policy(){};
FileStream_Policy(const FileStream_Policy& other)
{
file_name = other.file_name;
}
FileStream_Policy& operator=(const FileStream_Policy& other)
{
file_name = other.file_name;
return *this;
}
inline std::ofstream& Stream()
{
if ( !file_stream.is_open() )
file_stream.open(file_name, std::ofstream::out);// | std::ofstream::app
return file_stream;
}
inline std::wstring& FileName()
{
return file_name;
}
protected:
std::ofstream file_stream;
std::wstring file_name;
};
//Type Definition for a File Log using Logger<FileStream_Policy>
using FileLog = Logger<FileStream_Policy>;
class FileLog_Mgr
{
public:
static std::ostringstream& Get(int index, LogLevel level)
{
try
{
return Logs[index].Get(level);
}
catch ( int exception )
{
assert("Indexed Log does not exist");
exit(-404);
}
}
static int RegisterNewLog(std::wstring file_name)
{
if ( !ThreadRunning )
{
for ( int i = 0; i < Logs.size(); ++i )
{
if ( Logs[i].Output.FileName() == file_name )
return -2;
}
FileLog newLog;
newLog.Output.FileName() = file_name;
Logs.push_back(newLog);
return Logs.size() - 1;
}
else
{
return -1;
}
}
static bool CheckIndex(int index)
{
if ( index >= 0 && index < Logs.size() )
return true;
return false;
}
static bool macroCheck(int index, LogLevel level)
{
if ( index >= 0 && index < Logs.size() )
{
if ( level > Logs[index].ReportingLevel() || !Logs[index].Output.Stream() )
return false;
return true;
}
return false;
}
static bool Start()
{
if ( WtL_Thread.joinable() )
return false;
ThreadRunning = true;
WtL_Thread = std::thread(&FileLog_Mgr::WriteToLogs);
std::this_thread::sleep_for(std::chrono::milliseconds(StartDelay));
return true;
}
static bool Stop()
{
if ( WtL_Thread.joinable() )
{
ThreadRunning = false;
WtL_Thread.join();
return true;
}
return false;
}
protected:
static std::vector<FileLog> Logs;
private:
virtual ~FileLog_Mgr()
{
Stop();
}
static bool ThreadRunning;
static int WriteInterval;
static int StartDelay;
static std::thread WtL_Thread;
static void WriteToLogs()
{
while ( ThreadRunning )
{
for ( int i = 0; i < Logs.size(); ++i )
{
Logs[i].Output.Stream() << Logs[i].buffer.str();
Logs[i].buffer.str("");
Logs[i].Output.Stream().flush();
}
std::this_thread::sleep_for(std::chrono::milliseconds(WriteInterval));
}
//There might be buffered data
for ( int i = 0; i < Logs.size(); ++i )
{
Logs[i].Output.Stream() << Logs[i].buffer.str();
Logs[i].buffer.str("");
Logs[i].Output.Stream().flush();
}
}
};
}
#ifndef LOG_MAX_LEVEL
#define LOG_MAX_LEVEL (dbg::logFATAL + dbg::logERROR + dbg::logWARNING + dbg::logINFO + dbg::logDEBUG1 + dbg::logDEBUG2 + dbg::logDEBUG3 + dbg::logDEBUG4 )
#endif
#define LOGFILEX(index, level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(index, level) );
else dbg::FileLog_Mgr::Get(index, level)
#define LOGFILE1(level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(0, level) );
else dbg::FileLog_Mgr::Get(0, level)
#define LOGFILE2(level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(1, level) );
else dbg::FileLog_Mgr::Get(1, level)
#define LOGFILE3(level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(2, level) );
else dbg::FileLog_Mgr::Get(2, level)
#define LOGFILE4(level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(3, level) );
else dbg::FileLog_Mgr::Get(3, level)
#define LOGFILE5(level)
if ( level & ~LOG_MAX_LEVEL || !dbg::FileLog_Mgr::macroCheck(4, level) );
else dbg::FileLog_Mgr::Get(4, level)
#endif
正如评论中所讨论的,我无法真正运行您的代码,因为它不是一个最小的工作示例。但是在您尝试过之后,这似乎是静态初始化顺序的问题。
取代
static std::vector<xlog> logs;
通过函数
static std::vector<xlog>& getLogs() {
static std::vector<xlog> logs;
return logs;
}
并在您在register_log
中使用logs
的地方使用getLogs()
。因此,例如:
static int register_log(string x)
{
getLogs().push_back(x related thing);
return getLogs().size() - 1;
}
这将确保在将任何内容推送到向量之前构建向量。
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何在C++中使用非静态成员函数作为回调函数
- (C++)为什么静态成员可以在初始化之前使用
- 类的全局对象和静态成员
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 模板化类中静态成员的延迟初始化
- 使用静态成员声明类时遇到问题
- C++:是否可以使用非静态成员变量模板?
- 静态成员函数使用相同的名称时出现模板类型名称错误
- 无法在clang Linux中分配非静态成员函数,但我可以在Visual Studio Windows中分配
- 将 lambda 函数分配给静态成员变量 (c++)
- 类构造函数中的静态成员变量分配
- 静态对象的非静态成员分配在哪里
- 在静态成员分配之前调用函数
- 静态成员变量分配时间
- C++:我可以将非静态成员变量的值分配给静态成员变量吗?
- 使用单一实例分配静态成员
- 对于动态分配的静态成员变量,是否可以跳过delete操作?
- 类中的静态成员是如何分配的
- stl容器作为静态成员的内存分配