Log Class

Started by
8 comments, last by Rebooted 18 years, 1 month ago
In C++ * Does std::vector call the copy constructor when it resizes or does it just do a direct data copy? * Can you do polymorphism without pointers? Without virtual functions? * Can I make a static operator() ? For my log manager, you can add different log types, so I was thinking either inheritance or template classes. The template class would just be a wrapper for a log class that supports certain functions. Then I could pass the templated class to the manager. Otherwise the manager could store base class pointers. * Which would you choose? The second option has some overhead. * For template classes I have to define the class in the header?
Advertisement
std::vector will use the copy constructor and assignment operator where appropriate.

You can use polymorphism with references, but virtual functions are more or less necessary unless you want to implement the same functionality manually (not recommended).

operator() must be a non-static member.

Not clear on what you mean by your template implementation.

Template classes don't need to go into the header if your compiler implements the export keyword (practically none do) or if you use explicit template instantiation. However, in practice it's usually best to put the implementation in the header or some kind of inline file.
I'm wondering about std::vector, since it seems unnecessary to call the copy constructor (this is different from operator = ?). We can guarantee that there will only be one of the final object in the new allocated memory, so we aren't really copying, we are just moving.
1) I don't believe this is defined by the standard. I don't feel like looking it up right now. To be on the safe side, I would say "Don't rely on either behavior."
2) A little; if you aren't comfortable with it you should probably read some additional books on the language. Some forms of polymorphism, such as overloading, can be done without pointers. For example, foo::bar(int) and foo::bar(double) are polymorphic functions. Other forms, such as passing in a subclass and using its functions, require pointers. Virtual functions are about the only way to take advantage of subclasses.
3) Nope.
4) I would choose neither. See below.
5) Not necessarily. There is some variation between compilers on this issue, and you should check the documentation for your system.


Why not use one of the logging classes already out there (and [google]) that are debugged, often thread safe, and (in many cases) generate output readable through your debugger or operating system?

Some of the classes on that site will accept any object, and assuming you have a properly written operator<< for output, will display quite a bit of good stuff.

You can do some really nice things withe the TRACE macro or System.Diagnostics.Trace .NET class if you are doing managed c++. Some of those libraries also take advantage of that.
std::vector needs to call the copy constructor otherwise it wouldn't play nicely with classes that did things like RegisterInstance(this) in the constructor. If your copy constructor can be implemented in terms of a memcpy(), you're free to implement it that way yourself. Also, keep in mind that this behavior may change with the addition of move constructors in the next version of the C++ standard.
Here is an example.

class BMPWrapper: BMPHandle handle BMPWrapper():   handle = LoadBMP(FILE_NAME) copy(BMPWrapper &rhs):   // need to copy   handle = LoadBMP(rhs.BMPHandle.filename) ~BMPWrapper():   freeBMP(handle)


Here if we are truly making a copy, we need to load the BMP again. If we are just shuffling around the class in memory, it is not necessary. But yet this would not be efficient in a vector if it loaded all the BMPs every time the vector is resized.

So the solution would be to use memory managed handles, and only specifically duplicate when necessary? Or maybe store pointers in the vector.
Things with expensive copy construction/assignment semantics don't really belong in std::vectors. You can store (smart) pointers to objects instead, or use reference counted smart pointers for the implemenation of your object.
Maybe you can comment on which way is better? P.S. they probably won't compile, I am just looking at the idea.

Edit: In writing this, I am even wondering if it possible to use a template class to define an interface like this.

// template
template <class T>class Logger {  T log;  int setPriority(int x) { T.setPriority(x); }  int logString(const string& str) { T.logString(str); }}class LogManager {  list <Logger <?> > logList;}


// base class
class Logger {  virtual int setPriority(int) = 0;  virtual int logString(const string&) = 0;}class LogManager {  list <Logger> logList;}
The first one won't compile and the second one won't work since you're trying to store polymorphic objects by value. If you want the second to work you'll need to store (smart) pointers to your log objects.
You can only use templates for static polymorphism, decided at compile time. You need to use inheritance and virtual functions for dynamic polymorphism.

This topic is closed to new replies.

Advertisement