In my project, some classes are instantiated more than once. Each class logs some events. The logging method is a generic one used all around the project and it uses the standard cout. The log message contains the time, name of the class, name of the method, a variable value, and a custom message.
The disadvantage is that the log is not instance specific. I do not know which instance of the class wrote the log.
Is there a nice way to solve this problem without adding additional static members as instance counters to the classes? I am using boost and C++11. Maybe boost has something that might help.
The only solution I can think of is to include the instance address (this) to the log.
You will need to differentiate between different classes somewhere, these are a few options (all rely on some kind of ID):
Add some additional static variable.
Not an option for you, but in my opinion, the best way to go if you aim for readability.
Use this, as you suggested:
This obviously generates unique IDs, but they will tend to be unreadable and hard to distinguish with growing address lengths (as only one or two characters might differ in a lengthy address string). Also, the addresses are likely to change between every run of the application (especially when employing ASLR), so you won't be able to see which exact instance created which line of output (if that's required).
Use this and hash the value:
To be honest, I don't see much of a difference to 2), but it might trigger some further ideas. Some ugly hack could look like this:
#include <iostream>
#include <functional>
#include <cstddef>
class Logger
{
public:
static void log(void* ptr)
{
using hash_type = std::uintptr_t;
std::cout << std::hash<hash_type>{}(reinterpret_cast<hash_type>(ptr))
<< " logged something..." << std::endl;
}
};
You can also consider specializing std::hash for your classes and use that in the logging output. This would remove the problem of changing addresses between different runs, if implemented properly.
Generate an ID during construction (e.g. by passing some identifier to the constructor):
This is not really an option since you have no evidence or control that a unique ID is generated for each class - unless you use some kind of (abstract) factory with access to a private constructor or some kind of global registry (see below).
Use some helper utility where your logging classes are registered and unique IDs are generated (something like a registration class).
For simple logging purposes, IMHO this is bloat and does not add any value compared to 1).
Conclusion:
I would go for option 1) if readability for humans is of concern and for 2) if you simply want some number to distinguish between log messages (e.g. for piping and filtering).
You can quite easily generate IDs via CRTP adaptor like that (if you can modify your classes a bit)
template<typename T>
struct enable_id
{
int id = global_id++;
private:
static int global_id;
};
template<typename T>
int enable_id<T>::global_id = 0;
class foo : public enable_id<foo>
{
};
template<typename T>
void log(const T& t)
{
// if is_base_of
std::cout << t.id << std::endl;
}
The easier way to fix the problom is to print the address to indicate which object it is. As following:
cout<<static_cast<void*>(this)<<endl;
Or output some features.
I usually have a protected class member containing the time of instance's creation at the root of all my class hierarchies, at least at the debugging stage. Very helpful for multi-threaded applications also.
Convert this time to whatever you want - string, milliseconds, epoch time - and you have a unique id for each and every instance.
If there are only a few instances of class going to be, I would suggest you introduce a string member and initialize it with a unique name during object creation. It will help you in logs reading. By default, it may be initialized with object's address.
Related
I have a class with many objects that I would like to group in some type of container and also access them with some type of identifier.
class Menu {
Object title;
Object play;
Object instructions;
Object pause;
...
};
Having each object listed in the class, shown above, is nice because I can access them like, menu.title, but then I have to retype every name to add it to a container, vector.push_back(title).
Shown below is how I've always solved the problem. I use an enum's integer value to access the corresponding index. objects[TITLE] or objects[PLAY]
class Menu {
std::vector<Object> objects;
};
enum ObjectTypes {
TITLE, PLAY, INSTRUCTIONS, PAUSE, ...
};
I generally dislike this approach because it seems indirect, and when using nested classes and enums, the identifiers can become long and cumbersome. I'm coming from C and somewhat new to C++. Does anybody have a more practical and/or elegant way to solve this problem? C++11 and above welcomed!
The approach you are using is fine. If you want to avoid cumbersome identifiers, you can make a temporary reference to keep things more succinct. For example, instead of calling:
menu.objects[PAUSE].foo();
menu.objects[PAUSE].bar();
menu.objects[PAUSE].baz();
... you could do this when necessary:
Object & pause = menu.objects[PAUSE];
pause.foo();
pause.bar();
pause.baz();
and it would work the same, but without all of the redundant characters.
I think your approach is fine. Using a std::map<ObjectType, Object> instead of a std::vector might be a little more type-safe.
Either way, if you want to save yourself a little typing you could overload the operator[] on Menu:
Object& operator[](index_type i){ return objects[i]; }
const Object& operator[](index_type i) const { return objects[i]; }
Then you can write menu[TITLE].
Other than that, I don't see how it can be any less cumbersome, there is no redundant information there and, as Jeremy pointed out, if you need an object multiple times you can always create a local reference auto& title = menu[TITLE];.
Depending on what other responsibilities Menu has maybe you don't need a Menu class at all and you can just use a map or vector directly?
The best solution to your question depends mostly on your use cases.
I see two main use cases:
You want to represent "functions"of a "device" so you can achieve readable code when manipulating that "device" from your code. Such as a MediaPlayer device having play, stop, pause operations. But you dismissed the option to simply add member functions to your "device" object, such as Play(), because you want to re-use your play code also for another device, such as a tuner device. Also, you want to apply operations to all or a sub set of those "functions", for example Enable()/Disable()/ToString()/Trigger(),Configure()..., which is why the member function approach is not favorable.
You want to create a Document Object model, which is more data focused. Such as an Xml Document.
From what you wrote in your question, I assume you have use case 1 in mind. Your Object type has all the common operations you need.
Yet, then there are the differences between all those "functions".
In order to stick to your simple approach, you would need to manually set up/configure your Object instances, which might in the long run turn out to be annoying, but hardly avoidable:
// Example of "annoying": If you have more than 1 "device",
// you have to write such a function for each of them.
// Also, there is that fishy bit with Object.Id - the association between
// your configuration data and your object you want to configure.
void ConfigureMenu( std::vector& menuItems, MenuConfigurationData& configData )
{
for( auto& menuItem : menuItems )
{
menuItem.Configure( configData[menuItem.Id] ); // spoiler!
}
}
Also, I am inclined to think that even now you have some code not shown in your question, which configures your objects.
With that in mind, you might want to get rid of the idea to write 1 class type per "device" by hand. The next device/menu will need to be treated the same, yet with dedicated more coding.
So, my advice to you is to get rid of your class Menu for good, to abstract your problem and to model your problem rather like: Object is your "function" and a device is simply a set of functions/Objects. Then, your class Menu simply becomes an instance, named Menu.
typedef uint32_t FunctionId; // for example uint32_t...
typedef std::map<FunctionId,Object> Device; // aka. Menu.
Then, in the configuration function you most likely have anyway, you pass in an instance of that Device map and your configuration function fills it with Object, properly configured.
// those enums are still specific to your concrete device (here Menu) but
// you can consider the time it takes writing them an investment which will
// pay off later when you write your code, using your functions.
// You assign the function id which is used in your meta-data.
enum class MenuFunctions : FunctionId { play = ..., title = ..., instructions, ... };
// "generic" configuration function.
// Does not only configure your Object, but also puts it inside the device.
void ConfigureDevice( Device& device, ConfigData& configData )
{ // ...
}
And later in your code, you can access the functions like this:
menu[MenuFunctions::play].Trigger();
There are alternative approaches and variations to this, of course. For example, assuming you have your meta data (config data, device descriptions), you could stop coding all that by hand and instead write some code generator which does the job for you.
Your first version of such a generator could create your configuration functions and the enums for you.
With all that in place, the use case of "nested classes" becomes just a matter of creating collections of Device instances. Now, as all your devices are of the same type, you can compose and sub-group them at your leisure.
A few different approaches below. I'm not saying which is "best". There are pros/cons to them all.
A) Rather than using a vector (e.g. class Menu { std::vector<Object> objects; };), use an array class Menu {std::array<Object,NObjectTypes> objects;}; when your element count is constant.
B) Just use a class, but provide an api to return a std::array<> of references to your objects:
class Menu {
Object title;
Object play;
Object instructions;
Object pause;
...
std::array<Object*,NObjects> allObjects();
};
C) std::tuple can be useful when your types are not all the same.
For menus, I'll often go with "A".
Assume I want to implement class A which must load its "configuration" from a file. And let's assume the "configuration" is a simple map<string, string>.
I can implement the A::LoadConfiguration in two different ways:
void A::LoadConfiguration(string filename)
map<string, string> A::LoadConfiguration(string filename) const
Should I prefer either of the two implementations, and why?
If you prefer the second version when the user wants to get info on a file they will base all their algorithms on the map. If you do the second version, meaning the implementation may be a map, but doesn't have to be, they can base their code around an API which does not have to change even if the internal implementation does.
Consider the situation where later you realize it is far more efficient to use an std array, for whatever reason, now every program using this code has to change many of it's algorithms. Using the first version the change to array can be handled internally and reflect no changes on the outside.
Now if you are planning to make multiple instances of the class you will definitely want to make it a static method because you don't want the file to load every time you call the constructor (especially if the file will not change).
Completely ignoring your suggestions, but this is probably how I would do it (not knowing all your constraints, so ignore me if it does not fit):
class A
{
public:
static A fromConfiguration( string fileName );
/* ... */
}
In most cases, the "configuration" of a class should be set at object creation, so forcing the user to provide it on construction is a good thing (instead of having to remember to do do the loading later).
namespace NeatStuff
{
map<string,string> loadSimpleConfiguration( string fileName );
}
If the configuration file format is really simple (and not specific to your class) you can move the actual loading out of the class.
Assuming other classes use the configuration later, I prefer option 1, and an additional GetConfigurationParameter public const method that gets the config value for a particular key. That lets me make other classes which can just ask for some parameter by name without ever caring that it's implemented as a map.
Another reason why I prefer option 1 is that loading a configuration should be distinct from returning it. If I see a name like LoadConfiguration, I assume that it loads the config from somewhere and sets the parameters in the class. I do not assume it returns some description of the configuration, which I'd instead expect from a method like GetConfiguration - but opinions on this will vary for different people of course.
Given the following, working code.
#include <iostream>
template<class Detail>
class AbstractLogger
{
public:
static void log(const char* str) {
Detail::log_detailled(str);
}
};
class Logger : public AbstractLogger<Logger>
{
public:
static void log_detailled(const char* str) {
std::cerr << str << std::endl;
}
};
int main(void)
{
AbstractLogger<Logger>::log("main function running!");
return 0;
}
Now, I want to put AbstractLogger into a library, and let the library user define his own logger, like the Logger class here. This has one drawback: AbstractLogger<Logger> can not be used inside the library, since the library can not know Logger.
Notes:
Please no virtual functions or questions why not. Also, I am aware of the similar problem that "static virtual" members are invalid. Maybe, there is a workaround in CRTP :)
C++11 will be interesting, however, I need "usual" C++.
If what you mean is that you want to have a library that uses this as a logging mechanism without knowing the exact instantiating type, I would advice against it.
The only way of doing it while meeting your other requirements (i.e. no virtual functions) is that all your functions/types in the library that need to log are converted into templates that take the Logger type. The net result is that most of your interface becomes a template (although you can probably move a good amount of the implementation to non-templated code, it will make your life much harder than needed, and it will still generate a much larger binary).
If your concern with virtual functions is performance, then you should reconsider your approach and the problems it brings. In particular, logging is expensive. Most logging libraries tackle it by optimizing the non-logging case (by means of macros that avoid calling the logger if the log level/group/... are not enabled), but still leave dynamic dispatch for the actual writting. The cost of the dynamic dispatch is negligible compared with the cost of writing to the console, or a file, or even with the cost of generating the message that will be logged (I am assuming that you not only log literal strings)
The usual approach is to code against a concept, while providing helpers so that users may easily produce types that satisfy one or more of those concepts. As an example, something like boost::iterator_facade is a CRTP helper that makes it easier for a user to write an iterator. Then, that iterator can be used anywhere an iterator is accepted -- for instance in the range constructor of std::vector. Notice how that particular constructor has no foreknowledge of the user-defined type.
In your case, AbstractLogger would be the CRTP helper. The missing piece would be to define e.g. a logger concept. As a result, notice that everything that needs a logger either needs to be implemented as a template or you need a type-erasing container to hold arbitrary loggers.
Concept checks (like those provided by Boost) are convenient for this kind of programming, since they allow to represent a concept with actual code.
Template classes can't be 'put in a library' since they are instantiated by the compiler as specializations of their template parameters.
You may put parameter independent stuff used in the template implementation into a library though.
I have a slightly nasty setup which I am trying to figure out a good way to overhaul.
I have a class Fractal with a couple of pure virtual functions to do work. Each instance also has a human-readable name. I want to build a menu of all these subclasses so the user can switch between them - but, being lazy, I want to avoid having to both define each instance in its source file and list them all again in another. In other words, I want to build up this list of subclasses dynamically at runtime.
What I have done (and have working) so far is:
define a class FractalRegistry which is a singleton encapsulation of a std::map<std::string,Fractal*> (where the keys are the instance names),
have the base Fractal constructor register each instance by name with that registry (and for completeness the base ~Fractal deregister them),
statically instantiate each base class once (with its name, which is a constructor argument).
So for each new fractal I write something like this (paraphrased):
class SomeFractal : public Fractal {
public:
SomeFractal(std::string name, std::string desc) : Fractal(name,desc) {}
virtual void work_function(...) { ... }
}
SomeFractal sf_instance("Some fractal", "This is some fractal or other");
and the instance is added to the central list by the base class constructor, so I don't need to list it myself.
However, this leads to having a load of static instances lying around, which appear to vanish if I move this code into a library. (Yes I can add a horrid empty function to each compile unit so I can force its inclusion, or resort to linker trickery such as -Wl,--whole-archive, but these don't seem like the right answer either.)
Is there a better way? What I guess I'm looking for is a way to write these Fractal implementations - all of which have the same interface, so I thought subclasses of a base class would be ideal - and to keep and populate this central registry of them but without leaving myself the landmine of static instances.
What have I missed?
I should state that I've been working with C for years but don't really have the zen of C++, so there might well be something that would do the job staring me in the face... (If I was writing this in C I'd think about writing a second-order macro composite which both declared some function pointers and populated a table with them and the fractals' names and descriptions, but that's an even more Cish thing to do and it really doesn't seem right for C++.)
Edit:
What I am hoping to achieve is an elegant way of rearranging my code which makes it easy to add new fractal types and automatically populates a central list of them, but doesn't force the programmer to create a static instance of every fractal.
Recall that static libraries are pre-C++ technology, so it’s not unreasonable for their implementation to assume that unreferenced code is unwanted (as indeed it still is in C++ when one is not playing this particular trick).
As such you need to specify the object files explicitly for each executable that needs them, assuming you don’t want to explore more complicated approaches involving shared libraries, plugins, and so on. This should not be onerous: you must already have a list of the objects that go into the library, so instead of building a library add that list to the linker command line of your executables.
You'd need some kind of object to be created during app start up to handle the registration of the Fractals. Usually when I need to do this, I create a separate Registrar class, that handles the registration of types with a factory, and create an instance of that in the cpp file of each type the factory should know about.
registrar.h
class Registrar
{
Registrar(const std::string& name,
const std::string& desc,
Fractal*(*creator)())
{
FractalFactory::register(name, desc, creator);
}
};
#define REGISTER_FRACTAL(name, desc, type) \
namespace { \
Fractal *create##type() { \
return new type(); \
} \
Registrar register##type(name, desc, create##type); \
}
myfractal.cpp
class MyFractal : public Fractal
{
// fractal code
};
REGISTER_FRACTAL("MyFractal", "Creates a cool pattern", MyFractal);
I have a class which I can write like this:
class FileNameLoader
{
public:
virtual bool LoadFileNames(PluginLoader&) = 0;
virtual ~FileNameLoader(){}
};
Or this:
class FileNameLoader
{
public:
virtual bool LoadFileNames(PluginLoader&, Logger&) = 0;
virtual ~FileNameLoader(){}
};
The first one assumes that there is a member Logger& in the implementation of FileNameLoader. The second one does not. However, I have some classes which have a lot of methods which internally use Logger. So the second method would make me write more code in that case. Logger is a singleton for the moment. My guess is that it will remain that way. What is the more 'beautiful' of the two and why? What is the usual practice?
EDIT:
What if this class was not named Logger? :). I have a Builder also. How about then?
I don't see what extra advantage approach two has over one (even considering unit testing!), infact with two, you have to ensure that everywhere you call a particular method, a Logger is available to pass in - and that could make things complicated...
Once you construct an object with the logger, do you really see the need to change it? If not, why bother with approach two?
I prefer the second method as it allows for more robust black box testing. Also it makes the interface of the function clearer (the fact that it uses such a Logger object).
The first thing is to be sure that the Logger dependency is being provided by the user in either case. Presumably in the first case, the constructor for FileNameLoader takes a Logger& parameter?
In no case would I, under any circumstances, make the Logger a Singleton. Never, not ever, no way, no how. It's either an injected dependency, or else have a Log free function, or if you absolutely must, use a global reference to a std::ostream object as your universal default logger. A Singleton Logger class is a way of creating hurdles to testing, for absolutely no practical benefit. So what if some program does create two Logger objects? Why is that even bad, let alone worth creating trouble for yourself in order to prevent? One of the first things I find myself doing, in any sophisticated logging system, is creating a PrefixLogger which implements the Logger interface but prints a specified string at the start of all messages, to show some context. Singleton is incompatible with with this kind of dynamic flexibility.
The second thing, then, is to ask whether users are going to want to have a single FileNameLoader, and call LoadFileNames on it several times, with one logger the first time and another logger the second time.
If so, then you definitely want a Logger parameter to the function call, because an accessor to change the current Logger is (a) not a great API, and (b) impossible with a reference member anyway: you'd have to change to a pointer. You could perhaps make the logger parameter a pointer with a default value of 0, though, with 0 meaning "use the member variable". That would allow uses where the users initial setup code knows and cares about logging, but then that code hands the FileNameLoader object off to some other code that will call LoadFileNames, but doesn't know or care about logging.
If not, then the Logger dependency is an invariant for each instance of the class, and using a member variable is fine. I always worry slightly about reference member variables, but for reasons unrelated to this choice.
[Edit regarding the Builder: I think you can pretty much search and replace in my answer and it still holds. The crucial difference is whether "the Builder used by this FileNameLoader object" is invariant for a given object, or whether "the Builder used in the call" is something that callers to LoadFileNames need to configure on a per-call basis.
I might be slightly less adamant that Builder should not be a Singleton. Slightly. Might.]
In general I think less arguments equals better function. Typically, the more arguments a function has, the more "common" the function tends to become - this, in turn, can lead to large complicated functions that try to do everything.
Under the assumption that the Logger interface is for tracing, in this case I doubt the the user of the FileNameLoader class really wants to be concerned with providing the particular logging instance that should be used.
You can also probably apply the Law of Demeter as an argument against providing the logging instance on a function call.
Of course there will be specific times where this isn't appropriate. General examples might be:
For performance (should only be done after identification of specific performance issues).
To aid testing through mock objects (In this case I think a constructor is a more appropriate location, for logging remaining a singleton is probably a better option...)
I would stick with the first method and use the Logger as a singleton. Different sinks and identifying where data was logged from is a different problem altogether. Identifying the sink can be as simple or as complex as you want. For example (assuming Singleton<> is a base-class for singletons in your code):
class Logger : public Singleton<Logger>
{
public:
void Log(const std::string& _sink, const std::string& _data);
};
Your class:
class FileNameLoader
{
public:
virtual bool LoadFileNames(PluginLoader& _pluginLoader)
{
Logger.getSingleton().Log("FileNameLoader", "loading xyz");
};
virtual ~FileNameLoader(){}
};
You can have an inherently complex Log Manager with different sinks, different log-levels different outputs. Your Log() method on the log manager should support simple logging as described above, and then you can allow for more complex examples. For debugging purposes, for example, you could define different outputs for different sinks as well as having a combined log.
The approach to logging that I like best is to have a member of type Logger in my class (not a reference or pointer, but an actual object).
Depending on the logging infrastructure, that makes it possible to decide, on a per-class basis, where the output should go or which prefix to use.
This has the advantage over your second approach that you can't (accidentally) create a situation where members of the same class can not be easily identified as such in the logfiles.