Keywords: C , static object, temporary object
This article will gradually explain the use of static objects and temporary objects in the C program design with a simple example.
The beginning of the story
One day, I am writing a MFC program with complex memory structure. In order to see the memory data structure of my concern, I want to frequently bring a lot of data trace to the screen. When I do this, God, my CPU usage rate is 100%! At the same time that the vc.net is the efficiency of Vc.Net and my grandmat, I invite my collection of magic "dbwin", but I didn't expect that the efficiency did not improve much, and I also made my grand machine. All running Debug Edition The program prints the information on the "dbwin" window, so I am determined to write a trace. My idea is very simple, apply for a console, write the information.
First version: The birth of ugly duckling
I use the simplest technology, which needs to be added to a console when the program run is started, and it is automatically released at the end. So I use the C object characteristics. Write a class:
Class myconsole
{
PUBLIC:
Myconsole ()
{
m_bhaveconsole = allocconsole ();
}
~ Myconsole ()
{
IF (m_bhaveconsole)
FREECONSOLE ();
}
BOOL M_BHAVECONSOLE;
}
After having it, just define a global class object, you have the program start to get the console and end the benefits of auto-release. Then add the following code:
#include
#undef trace
#define trace_cprintf
Define the global THEAPP to write on the XApp.cpp:
Myconsole theconsole; // This we have a globally available console! ! !
XAPP theApp;
Ok, compile, run, now, all TRACE is printed on console.
However, the first ugly duckling has a lot of shortcomings. First, every time you use the user's code, we want to write the code that users can run if you only need a #include header file, and you must add MyConsole Theconsole in the CPP file. This makes my heart like fried. However, the object entity cannot be added to the .h file. I have begun to think of a static class member, but this is not included in more .CPP, otherwise the link will have an error. So I thought static objects.
Second Edition: Nirvana before the swan
I change my myTrace.h to the following
#ifndef myTrace_HPP
#define myTrace_HPP
#include
Class myconsole
{
PUBLIC:
Myconsole ()
{
m_bhaveconsole = allocconsole ();
}
~ Myconsole ()
{
IF (m_bhaveconsole)
FREECONSOLE ();
}
BOOL M_BHAVECONSOLE;
}
Class myTracecondition
{
PUBLIC:
Static fun ()
{
Static myconsole theconsole;
}
}
#undef trace
#define trace mytracecondition :: fun (); _ CPRINTF
#ENDIF
Here I use a static object to be used for the first time, pay attention to it with a global static object (including a static class is also a global static deformation). Static class objects are constructed in the first use, and it is not recreated in repeated use, that is, you can verify this: myconsole ()
{
m_bhaveconsole = allocconsole ();
_CPrintf ("alloc / n");
}
~ Myconsole ()
{
IF (m_bhaveconsole)
{
_cprintf ("free / n");
FREECONSOLE ();
}
You will find "alloc" when you first call Trace. With the use of static objects, we can hide an object entity in .h file, do not need to bother the user's code. And this method is also high efficient, efficient and global objects. However, when you run more than two threads in my project, I have a new issue. You have seen that this way of calling TRACE is not a thread safe, at least make the printing information mess together. You may think of using threads safe CRT version, don't do it, most of the code is not needed, if the overall code efficiency is lowered, it is not worth it.
So I started to add a critical area in .h file. All threads are required to enter the same critical regions when the _cprintf calls TRACE. So I must packed the _cprintf. I can't use the global critical area, because this will cause me to make a .cpp file, and I can't use the use of static classes. So do ordinary class members do critical regions? NO!, So that each call is not a critical area. So maybe you guessed.
- I used a static object for the second time!
#include
Class myTrace
{
PUBLIC:
MyTrace (): ptracefun (_cprintf)
{
Static ccomautocriticalsection thecriticalsection;
PCRITICALSECTION = & ThecriticalSection;
PCRITICALSECTION-> LOCK ();
}
~ Mytrace ()
{
PCRITICALSECTION-> UNLOCK ();
}
INT (* ptracefun) (const char *, ...);
Private:
Ccomautocriticalsection * pcriticalsection;
}
Now, no matter how you use it, you will enter the same critical area.
Ok, now #define trace ...,, gold! I made a big mistake, I simply didn't write the redemption of Trace. How to use MyTrace? Is it written
#define trace mytracecondition :: fun (); /
Mytrace traceTMP; /
(* TRACETMP. PTRACEFUN)
No, I can't know how the user will use Trace. Maybe they are more willing to use N times in a pair of {}, that this code has undoubtedly become cancer.
So, the spirit of light flashed, I found the key to become swan
Third edition: Be a beautiful swan
Haha, I change the content of the header to this way.
#ifndef myTrace_HPP
#define myTrace_HPP
#include
#include
Class myTrace
{
PUBLIC:
MyTrace (): ptracefun (_cprintf)
{
Static ccomautocriticalsection thecriticalsection;
PCRITICALSECTION = & ThecriticalSection;
PCRITICALSECTION-> LOCK ();
}
~ Mytrace ()
{
PCRITICALSECTION-> UNLOCK ();
}
INT (* ptracefun) (const char *, ...);
Private:
Ccomautocriticalsection * pcriticalsection;
}
Class myconsole
{
PUBLIC:
Myconsole ()
{
m_bhaveconsole = allocconsole ();
}
~ Myconsole ()
{
IF (m_bhaveconsole)
FREECONSOLE ();
}
BOOL M_BHAVECONSOLE;
}
Class myTracecondition
{
PUBLIC:
Static myTrace Fun ()
{
Static myconsole theconsole;
Return mytrace ();
}
}
#undef trace
#define trace (* mytracecondition :: fun (). PTRACEFUN)
#ENDIF
Haha, you saw, I used the characteristics of the temporary object, and the temporary object was automatically destructed when the interim target (in this example, at the time of TRACE execution), so that the above automatically generates a critical area. . And there is no explicit object production. Print some things in MyTrace's constructors and designer functions, you can also see the construction and secting process of temporary objects. Lessons Learned
Temporary objects often have to be cautious, static objects are not all clear, but as a C FAN, there is always a need for creative thinking to use the powerful characteristics of the language, and some of the easy error of language is reasonable to use It is often possible to make the program. I hope to see this article, help you, C long live.
My gongs
My dance is messy