C ++ FAQ LITE [16] - Free Storage (FREESTORE) management (below)

zhaozj2021-02-08  226

[16] Free Storage (Part Of C FAQ Lite, Copyright? 1991-2001, Marshall Cline, Cline@parashift.com)

体,, nicrosoft @ sunistudio.com (East day production room, East day document)

FAQS in section [16]:

[16.19] C has an array that can be specified in the running period? [16.20] How to make the class always created instead of local or global / static objects through NEW? [16.21] How to make a simple reference count? [16.22] How to provide a reference count with a copy-on-write semantic semantic? [16.23] How to provide a reference to a copy-on-write semantic quota for derived classes? [16.24] Can you absolutely prevent others from destroying the reference counting mechanism? If you can, would you do this? [16.25] Can I use garbage collection in C ? [16.26] What is the two garbage collectors of C ? [16.27] Where can I get more C garbage collection information?

[16.19] C has an array that can be specified in the running period?

[Recently Changed SO IT Uses New-Style Headers and the Std :: Syntax and Reworded References To STL (on 7/00). Click Here To Go To The next FAQ in The "chain" of Recent Changes .

Yes, it is a standard library with a std :: Vector template to provide this behavior.

No, it is necessary to specify its length in the compile period based on the type of built-in group.

Yes, it is based on even for the inner application type, you can specify the awareness of the first dimension of the first dimension. For example, look at the previous FAQ, if you only need the number of dimensions of the first dimension of the array, you can apply for an array of new arrays instead of a pointer to multiple arrays:

Const unsigned ncols = 100; // ncols = array column number class fred {/ / {/}; void manipulateArray (unsigned nrows) // nROWS = array {FRED (* matrix) [ncols] = New Fred [nROWS] [NCOLS]; // ... delete [] matrix;}

If you need it not to change the number of first dimensional numbers in the runtime, you can't do this.

But don't have to use arrays. Because the array will bring trouble. If you can, use some types of objects. I have to use an array.

[TOP | BOTTOM | Previous Section | Next Section]

[16.20] How to make the class always created instead of local or global / static objects through NEW?

Use a named constructor usage.

As naming constructor usage, all constructor is private: or protected:, and there is one or more public static create () methods (therefore called "named constructor, named constructors), each The constructor corresponds to one. At this point, the Create () method allocates an object through NEW. Since the constructor itself is not public, there is no other way to create the object of the class. Class Fred {public: // create () method is "Name Constructor, Named Construction": static fred * create () {return new fred ();} static fred * create (int i) {return new fred (i );} Static fred * create (const fred & fred);} // ... private: // constructor itself is private or protected: fred (); Fred (INT i); Fred Const fred & fred); // ...};

In this way, the only way to create a Fred object is to pass Fred :: Create ():

INT main () {fred * p = fred :: create (5); // ... delete p;

If you want Fred to be derived, you must confirm that the constructor is in protected: section.

Note that if you want to allow the Fred class to become a member of the Wilma class, Wilma can be used as Fred's friend. Of course, this will soften the initial goal, that is, forcing Fred objects always allocated through New.

[TOP | BOTTOM | Previous Section | Next Section]

[16.21] How to make a simple reference count?

[Recently Moved Definition of Fred :: Create () Methods Below The Definition of Class Fredptr (ON 4/01). Click Here To Go To The Next Faq in The "Chain" of Recent Changes .

If you need to distribute multiple pointers that point to the same object, and when the last pointer disappears, you can use the following "Smart Pointer" class:

// Fred.h class fredptr; Class Fred {public: Fred (): count_ (0) /*...*/ {} // All constructor must set count_ to 0! // ... private: Friend Fredptr; // Friends class unsigned count_; // count_ must be initialized by all constructor // count_} point to the number of FredPtr images}; class fredptr {public: fred * operator-> () {Return P_;} Fred & operator * () {return * p_;} Fredptr (Fred * P): p_ (p) { p _-> count_;} // p cannot be null ~ fredptr () {if (--p_-> count_ == 0) delete p_;} FredPtr (const fredptr & p): p_ (p.p_) { p _-> count_;} Fredptr & Operator = (constftr & p) {// Do not change the order of these statements! / / (In order appropriately handled self-assignment) p.p _-> count_; if (--p_-> count_ == 0) delete p_; p_ = p.p_; return * this;} private: Fred * p_; // p_ will never be null}; nature, you can use the nested class to rename FredPtr to Fred :: Ptr.

Note that in the constructor, the copy constructor, the assignment operator, and the destructor, it can soften the above "Not far from NULL" rules. If you do this, it is better to put a p_! = Null check in the "*" and "->" operators (at least one assert ()). I don't recommend Operator Fred * () because it may make people unexpectedly get fred *.

One of FredPtr's implicit constraints is that it may point to Fred objects allocated through the New. If you want to be truly safe, you can make all the Fred constructor into private, add a PUBLIC (Static) Create () method (Static) Create () method that uses New with New to assign a Fred object and return a FredPtr (not fred *). constraint. This approach is the only way to create a Fred object to get a FredPtr ("Fred * P = New Fred ()" will be replaced by "Fredptr P = Fred :: Create ()"). This will accidentally destroy the mechanism of the reference count.

For example, if fred has a Fred :: Fred () and a Fred :: Fred (INT i, INT J), Class Fred will become:

Class Fred {public: static Fredptr Create (); // Defines the following Class FredPtr {...} Static Fredptr Create (INT I, INT J); // Defines the following Class FredPtr {...} // .. Private: fred (); fred (int i, int j); // ...}; class fredptr {/ * ... * /}; inline Fredptr Fred :: Create () {return new fred (); } Inline Fredptr Fred :: Create (INT I, INT J) {Return New Fred (i, j);} The final result is that you now have a way to use a simple reference count to provide "pointer semantics (Pointer Semantics ". The Fred class user explicitly uses the FredPtr object, which is more or less similar to the Fred * pointer. The benefit of this is that the user can build a copy of multiple FredPtr "Smart Pointer" objects, when the last FredPtr object disappears, the Fred object it points to it will be released.

If you want to give the user in "reference semant" instead of "pointer semant", you can use the reference count to provide "Copy ON Write" .

[TOP | BOTTOM | Previous Section | Next Section]

[16.22] How to provide a reference count with a copy-on-write semantic semantic?

[Recently Rewrote The First Paragraph for Clarity THANKS TO FABRICE CLERC (ON 7/00). Click Here to Go To The next FAQ in The "Chain" of Recent Changes . ]

The reference count can be done by a pointer semantic or reference semantic. The front FAQ shows how to use the pointer semantic reference count. This FAQ will display how to use the reference semantic reference count.

Basic thinking is to allow users to think they are replicating Fred objects, but actually real implementation does not copy until some users try to modify the implicit Fred objects to perform real replication.

Fred :: DATA class loads all the data of the Fred class. Fred :: Data also has an additional member count_ to manage reference counts. The Fred class finally became a "smart pointer" (internal) pointing to Fred :: DATA.

Class Fred {public: fred (); // Default constructor Fred (INT i, INT J); // Ordinary configuration in function Fred (const fred & f); fred & operator = (const fly & f); ~ fred () Void sampleinspectormethod () const; // this object does not change void samplemutatorthod (); // will change this O object // ... private: class data {public: data (); data (int i, int J) Data (const Data & D); // Since only fred can access the Fred :: Data object, // As long as you like, you can make the data of Fred :: Data as public, // But if you make you unhappy, just Data as private // also use Friend Fred; make FRED becomes a friend class // ... unsigned count_; // count_ is pointing to the number of this Fred objects // count_m must be initialized by all constructor to 1 // (From 1 because it is created in the Fred object referred to)}; Data * Data_;}; fred :: data :: data (): count_ (1) / * Initializing other data * / {} fred :: Data :: Data (INT i, INT J): Count_ (1) / * Initializing other data * / {} fred :: data :: data (const data & d): count_ (1) / * Initializing other data * / {} Fred :: fred (): DATA_ (New Data ()) {} fred :: Fred (INT i, INT J): DATA_ (New Data (i, j)) {} fr Ed :: Fred (Const Fred & f): DATA_ (F.Data_) { Data_-> Count_;} Fred & Fred :: Operator = (Const Fred & f) {// Don't make the order of these statements! // (in the order appropriately handled the self-assignment) f.data _-> count_; if (--data _-> count_ == 0) delete data_; data_ = f.data_; return * this;} fred: : ~ Fred () {if (--data _-> count_ == 0) Delete Data_;} void fred :: sampleinspectorthod () const {// This method is committed ("const") does not change anything in * Data_ // In addition, any data access will simply use "DATA _-> ..."} void fred :: samplemuttorMethod () {// This method may need to change the data in DATA_ // So first check if this Unique pointing * DATA_ IF (data _-> count_> 1) {data * d = new data (* data_);

// Call Fred :: Data copy constructor - data_-> count_; data_ = D;} assert (data _-> count_ == 1); // Now this method is often "DATA _-> ..." Access} If the default constructor is called very often, you can share a public Fred :: Data object for all Fred :: Fred () constructed to eliminate those NEW calls. To avoid static initialization, the shared Fred :: Data object is created when "first use" in a function. The following is a change to the above code (note that the destructive function of the shared Fred :: Data object will never be called; if this is a problem, you can solve the problem of static initialization order, or index to return to the above description Methods):

Class Fred {public: // ... private: // ... static data * defaultdata ();}; fred :: fred (): DATA_ () (DEFAULTDATA ()) { data _-> count_;} fred: : Data * fred :: defaultData () {static data * p = null; if (p == null) {p = new data (); p-> count_; // Make sure it does not become 0} Return P }

Note: If FRED is usually used as a base class, you can also provide a reference count for the class level.

[TOP | BOTTOM | Previous Section | Next Section]

[16.23] How to provide a reference to a copy-on-write semantic quota for derived classes?

[Recently Changed So It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The Next FAQ in The "Chain" of Recent Changes .]

The previous FAQ gives reference semantic reference counting strategies, but so far, for a single class rather than a class of classes. The technology prior to this FAQ extension is allowed to provide reference counts for class levels. Basic differences are that Fred :: Data is the root of the class level, which may make it have some virtual functions. Note that the Fred class still does not have any virtual functions.

The fictional creation function is used to build a copy of the Fred :: Data object. To choose which derive class created, the following sample code uses the name constructor usage, but there are other techniques (add a Switch statement in the constructor, etc.). The sample code is assumed to have two derived classes: DER1 and DER2. The method of derived class does not matter the reference count.

Class Fred {public: Static Fred Create1 (const st: string & s, int i); static fred create2 (float x, float y); fred (const fly & f); fred & operator = (const fly & f); ~ fred ( ); Void sampleinspectorthod () const; // this object will not be changed by void samplemuttorMethod (); // will change the THIS object // ... private: class data {public: data (): count_ (1) {} DATA (Const Data & D): count_ (1) {} // Do not copy 'count_' member! Data & Operator = (const data ";} / / Do not copy 'count_' member! Virtual ~ data () {assert (count_ == 0);} // false preceding function Virtual data * clone () const = 0; // Fiction Function Virtual Void Sampleinspectorthod () const = 0; // Pure virtual function virtual void sampleMutatorMethod () = 0; private: unsigned count_; // count_ need not be a friend Fred protected; // allow access to Fred count_}; class Der1: public Data {public: Der1 (const std :: string & s, int I); Virtual Void Sampleinspectormethod () const; virtual void SamplemutatorThod (); Virtual Data * Clone () const; // ...}; Class Der2: public data {public: der2 (float x, float y); Virtual VoID Sampleinspectormethod () const; virtual void samplemutatorthod (); Virtual data * clone () const; // ...}; fred (data * data); // Create a Fred intelligent reference to * data // it is private To force users to use createxxxxx () methods // requirements: DATA will be NULL DATA * DATA_; // INVARIANT: DATA_ IS NULL}; fred :: fred (data * data): DATA_ (DATA) {Assert (data! = NULL);} fred f Red :: Create1 (Const std :: string & s, int i) {return Fred (New Der1 (S, I));

} Fred Fred :: Create2 (FLOAT X, FLOAT Y) {Return Fred (New Der2 (x, y));} Fred :: Data * Fred :: Der1 :: Clone () const {return new der1 (* this) } Fred :: Data * Fred :: Der2 :: Clone () const {return new der2 (* this);} fred :: fred (const fly): data_ (f.data_) { data _-> count_ ;} Fred & fred :: Operator = (const fred & f) {// Don't even more the order of these statements! // (in the order appropriately handled the self-assignment) f.data _-> count_; if (--data _-> count_ == 0) delete data_; data_ = f.data_; return * this;} fred: : ~ Fred () {if (--data _-> count_ == 0) Delete Data_;} void fred :: sampleinspectorthod () const {// This method is committed ("const") does not change anything in * Data_ / / So we only need to "pass the method directly" to * data_: data _-> sampleinspectormethod ();} void fred :: samplemuttorMethod () {// This method may need to be more * DATA_ // So first check Whether this is the only point to * DATA_ IF (data _-> count_> 1) {data * d = data _-> clone (); // Factory function usage - data _-> count_; data_ = d;} assert (data_- > count_ == 1); // Now "directly pass the method to" * DATA_: DATA _-> Sampleinspectormethod ();} Nature, Fred :: Der1 and Fred :: DER2 constructor and Samplexxx method will need to be someworthy Appropriate implementation of the way.

[TOP | BOTTOM | Previous Section | Next Section]

[16.24] Can you absolutely prevent others from destroying the reference counting mechanism? If you can, would you do this?

[Recently Created (on 4/01). Click Here to Go To The Next FAQ in The "Chain" of Recent Changes .

No, (usually) will not.

There are two basic ways to damage the reference counting mechanism:

This policy will be destroyed if someone gets fred * (instead of impulsive FredPtr). If the FredPtr class returns a Fred & Operator * (), it is possible to get fred *: fredptr p = fred :: create (); fred * p2 = & * p ;. Yes, that is strange, not expected, but it may happen. This vulnerability has two ways to compensate: Reserving Fred :: Operator & () Let it return to a fredptr, or change the return type of FredPtr :: Operator * () so that it returns a FredRef (FredRef is a class; it There is a need to have all methods owned by FRED, and you need to transfer these methods to an implicit Fred object; the second option may become a performance bottleneck, depending on the performance of the compiler in the inline method). Another method is to eliminate FredPtr :: Operator * () - the ability to achieve and use Fred & to use Fred & ability. But even if you do this, some people can still pass explicit calls Operator -> (): fredptr p = fred :: create (); fred * p2 = p.operator -> (); come to get a Fred * . If someone has a leaking and / or suspended FredPtr pointer, the policy will be destroyed. Basically we say that fred is safe, but we can't prevent others from doing stupid things to the FredPtr object. (And if we can solve the FredPtrPtr object, there is still the same problem for FredPtrptr.). One of the vulnerabilities here is if someone creates a FredPtr, and FredPtr may have a leak (the worst case here is leaking, but it is usually better than the suspended pointer). This vulnerability can be made by declaring the FredPtr :: Operator New () to Private to prevent New FredPtr (). Another vulnerability here is if someone creates a local FredPtr object, you can get the address of FredPtr and pass it to FredPtr *. If the FredPtr * Life is longer than FredPtr, it may become a pointer to a flutter-shaking. The vulnerability can make up by preventing the address of the FredPtr (overloading FredPtr :: Operator & () is private), which will lose some functions. But even if you do this, they just do this: Fredptr P; ... FredPtr & Q = P; (or to pass FredPtr & what other), FredPtr * can still create FredPtr * with the same dangerous FredPtr &. Also, even if we make up for all the vulnerabilities, C is also called the syntax of the Pointer Cast. With one or two pointers to convert, a intentional programmer can create a loophole that is great enough to pass through a truck.

The lesson here is: (a) No matter how wise, it is impossible to prevent spies, (b) You can simply prevent errors.

So I suggest: use easy to use the mechanism to prevent errors, don't worry about trying to prevent spies. Even if you are trying to do, you will not succeed, you can't get lost.

If you can't use the C language itself to prevent spies, have other methods? Have. I personally use the old style code. Because spy skills typically include some singular grammar and / or Union (Union), you can use tools to point out most "right and wrong". [TOP | BOTTOM | Previous Section | Next Section]

[16.25] Can I use garbage collection in C ?

[Recently Created Thanks to Hans Boehm (on 7/00). Click Here to Go To The next FAQ in The "Chain" of Recent Changes .

can.

Garbage collection techniques are compared to the "intelligent pointer" technology described above:

Lower usually more efficient (especially when the average object size is small or multi-threaded environment) "cycles)" (if the data structure can form cycle, the reference counting technology usually has "leak") sometimes It will leak other objects (due to the necessary conservatives necessary for the garbage collector, sometimes it appears to be a distribution unit that is a random mode of the pointer, especially if the allocation unit is large, it may cause the assignment unit to have a leakage. Working with existing libraries (it is difficult to integrate into existing libraries because smart pointers need to be explicitly used.

[TOP | BOTTOM | Previous Section | Next Section]

[16.26] What is the two garbage collectors of C ?

[Recently Created Thanks to Hans Boehm (on 7/00) And Added a Url for Bartlett's Collector Thanks to Abhishek (on 4/01). Click Here to Go To The next FAQ in The "chain" of Recent Changes .

Usually, there is a C garbage collector with two flavors:

Conservative garbage collector. These garbage collectors don't know much about the distribution of stacks and C objects, just look for bit modes that look like pointers. In practice, work together with C and C code, especially the average object size, there are some examples, in alphabetical order:

Boehm-Demers-WEISER Collector Geodesic Systems Collector Mixed garbage collector. These garbage collectors are usually appropriately scanned, but the programmer needs to provide the layout information of the heap object. This requires programmers to do more work, but the result is to improve performance. Here are some examples, in alphabetical order:

Bartlett's Mostly Copying Collector Attardi and Flagella's CMM (if anyone has URL, please send it to me).

Since the C garbage collector is usually conservative, if a bit mode "looks" like a pointer to another unused block, there will be leaks. When the pointer to a block actually exceeds the block (this is illegal, some programmers will cross the limit; 唉) and (very little) When a pointer is hidden by the compiler, it will also make it confused. In practice, these problems are usually not serious, but these situations may be improved if the collector has some prompts about the object layout. [TOP | BOTTOM | Previous Section | Next Section]

[16.27] Where can I get more C garbage collection information?

[Recently Created (on 7/00). Click Here to Go To The next FAQ in The "Chain" of Recent Changes .

For more information, see Waste Collection FAQ for details.

[TOP | BOTTOM | Previous Section | Next Section]

E-mail the author [C FAQ Lite | Table of Contents | Subject Index | About The Author | | Download Your Own Copy] Revised Apr 8, 2001

转载请注明原文地址:https://www.9cbs.com/read-2076.html

New Post(0)