C + + Common knowledge (c + + must be known) Notes (ii) __c++

Source: Internet
Author: User
Tags exception handling

This article is a continuation of the first note.

17.Factory method Mode

An advanced design typically requires an object of the "appropriate" type to be created based on an existing object type. For example, we might have a pointer or reference to a type of employee object, and now we need to generate an appropriate Hrinfo object for that type of employee, as shown in the figure:

In general, we will use two bad ways:

Using a "type encoding" and a switch
Class Employee
{
Public
Enum Type{salary,hourly,temp};
Type type () {return type_;}
...
Private
Type Type_;
...
};
Hrinfo *geninfo (const Employee *e)
{
Switch (E.TYPE_)
Case SALARY:
Case Hourly:return New Stdinfo (e);
Case Temp:return New Tempinfo (e);
Default:return 0; Unknown type
}
Use dynamic_cast to ask for information
Hrinfo *geninfo (const Employee *e)
{
if (const Salary *s=dynamic_cast (E))
return new Stdinfo (s);
else if (const hourly *h=dynamic_cast (E))
return new Stdinfo (s);
else if (const Temp *t=dynamic_cast (E))
return new Tempinfo (s);
Else
return 0;
}

The main disadvantage of these two implementations is that they are coupled to the specific types that derive from employee and Hrinfo, and when we maintain code, we have to manually do a lot of code editing if we do not have a clear or corresponding generation relationship with two classes and we ignore their changes. And this can easily lead to error generation.

Now let's analyze the crux of the problem: how to handle the mapping of employee to Hrinfo type. In the words of the book, who knows the most about the Hrinfo object that temp employee needs. Of course, is temp employee himself. Well, now that you know what the key is, the way out:

Class Employee

{

Public

...

Virtual Hrinfo *geninfo () const = 0; Factory method

...

};

Class Temp:public Employee

{

Public

...

Tempinfo *geninfo () const

{return new Tempinfo (*this);}

...

};

The essence of Factory method is that the base class provides a virtual function "hook" for producing the appropriate "product". And each derived class can override the integrated virtual function to produce the appropriate product for itself. In fact, we have the ability to use one type object to produce another object of unknown type. Using the factory method pattern usually means that an advanced design needs to produce another "appropriate" object based on the exact type of an object, which often occurs when multiple parallel or almost parallel class hierarchies exist.

18. Covariant return type

In general, an overridden function must have the same return type as the function that was overridden by it. However, the situation is somewhat relaxed for the covariant return type (covariant returns type).

In simple terms, if a function's return value is a class, then it is rewritten that a subsequent return value can make the Class A derived class. As follows:

Class shape{

Public

Virtual shape* clone () const=0;

};

Class Cricle:public Shape

{

Public

Cricle *clone () const; The return value type is cricle * and has a derived relationship from the original shape*

}

19. No copying

The access restriction modifier public/private/protected can be used for advanced constraint techniques to indicate how a class can be used.

Class nocopy{

Public

nocopy (int);

Private

Nocopy (const nocopy &); Copy Constructors

Nocopy &operator = (const nocopy &); Assignment constructors

};

If the above two constructors are not declared private, the compiler will secretly declare them as shared, inline member functions.

Note: By deliberately declaring a copy constructor and an assignment constructor as a private member, you can limit the compiler's own implicit addition of constructors and prevent direct calls to these two member functions in your program ...

20. Prohibit or force the use of heap heap distribution

The use of heap allocation is prohibited in order to ensure that the destructor of the object is called. The handle object (handle object) that maintains a reference count on the Ontology object (Body objects) belongs to this object. A local object of a class that has an automatic store, whose destructor is invoked automatically (except for the exception of an abnormal program termination that occurs through Exit/abort), and a class object with a static store automatically calls the destructor, but the object that is assigned must display the destruction.

Prohibit heap allocation:

Class noheap{

Public

...

Protected://declared as protected because the destructor or constructor of the base class might implicitly call the

void *operator New (size_t) {return 0;}

void operator delete (void *) {}

Private

Prohibit assigning arrays

void *operator new[] (size_t) {return 0;}

void operator delete[] (void *);

}

In the above code, the size_t parameter is automatically initialized to the size of the Noheap object (in words), and void * is automatically set by the compiler to the address of the object that will be delete.

To encourage the use of pair allocations, simply declare the new/delete as public and then modify it to:

Noheap *operator New (size_t) {return new (size_t);}

void operator Delate (void*) {delete this;}

21. Positioning new (placement new)

(http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10 can be viewed first)

The simplest use of placement new is to place an object in a specified memory location, which is in the global namespace Std.

void *operator New (size_t,void *p) throw ()

{return 0;}

The implementation of placement new ignores the argument representing "size": size_t, which returns its second argument directly. Placement new allows us to "place" objects in a particular position, acting a bit like calling a constructor.

Class sport{...}; Represents a serial port

const int comloc=0x00400000; Represents the space position of a serial port

....

void *comaddr=reinterpret_cast (Comloc); Converts an int type of data into a void* type

Sport *com1=new (COMADDR) sport; Creates a sport object in the Comloc location, size_t automatically initialized to the size of the sport object (in bytes)

The above code also shows how to define a serial port.

Placement New is a version of function operator new, which does not actually allocate any storage, and simply returns one (possibly) pointer to the allocated space. It is important that you do not delete a call to placement new because it does not have space allocated. We can destroy an object by displaying a destructor of the calling class.

We can also create an array of objects in a particular location space:

const int numcoms=4;

...

Sport *comport=new (COMADDR) sport[numcoms]; Create an array at the COMADDR location

Finally to destroy:

int i=numcoms;

while (i)

{

Comport[-i].~sport ();

}

Instance:

Code that attaches a new value to a simple, fixed-size buffer:

String *sbuf=new String[bufsiz]; Call the default constructor for string

int size=0;

void Append (String buf[],int &size,const string &val)

{buf[size++]=val;} The assignment constructor is called here, so that the string default constructor is called more

You can use placement new to avoid the execution of the following default initialization code:

Const size_t n=sizeof (String) * bufsize;

String *subf=static_cast (:: operator new (n));

int size = 0;

The specific code is as follows:

int size=0;

void Append (String buf[],int &size,const string &val)

{

New (&buf[size++]) string (val); Placement new, calling the copy constructor

}

The above two append () functions also embody the difference between the copy constructor and the assignment constructor ...

Usually use placement new to do some cleanup work:

void Cleanupbuf (string buf[],int size)

{

while (size)

{

Buf[-size].~string (); Destroying an initialized element

:: operator Delete (BUF); Free Storage Area

}

}

This technology is widely used in the implementation of most standard libraries.

22. Array allocation

C + + programmers know that when allocating and returning memory, the matching of an array and a non array operator is maintained:

T *at=new t;

Delete at;

T *aryt=new t[12];

delete [] Aryt;

In addition, if you customize new and delete for non arrays, it's best to define new[]/delete[at the same time. The form is as follows:

void *operator New (size_t) throw (Bad_alloc)

{

Return:: operator new (size_t);

}

void *operator new[] (size_t) throw (Bad_alloc)

{

Return:: operator new[] (size_t);

}

void operator delete (void *) throw ();

{

Return:: operator deletes at;

}

void operator delete[] (void *) throw ();

{

Return:: operator deletes [] at;

}

When the array new is implicitly invoked with the new expression, the compiler often slightly increases some memory requests:

Aryt=new T[5]; The amount of memory requested is 5*sizeof (T) +delta byte

The requested extra space is used for Run-time memory Manager (runtime memory manager) records some information about the array (including the number of allocated elements, the size of each element, and so on) is essential for later recovery of memory. However, the compiler does not necessarily request additional memory space for each array allocation, and the amount of extra requested memory space varies for different array allocations.

23. Exception Security Axiom

Writing an unusually secure program or library is a bit like the proof theorem in Euclidean geometry: proving some simple theorems with the smallest possible set of axioms, and then using these auxiliary theorems to prove later more complex and meaningful theorems.

Handling exception security issues like this: building an exception-safe code from an exceptionally secure component. However, simply combining a set of unusually secure components or function calls does not guarantee that the resulting result is type-safe.

Axiom 1. The exception is synchronized

The exception is synchronized and occurs only at the boundary of the function call . Therefore, some basic operations do not produce an exception. The translator's understanding of "sync" is that if a program throws an exception at a point, the program will not continue to execute until the exception is processed.

Axiom 2. The destruction of objects is safe.

This axiom is based on the consensus of many C + + communities.

Axiom 3. The swap operation does not throw an exception

The same axiom is based on the consensus of many C + + communities.

24. Exception Security function

The hardest part of writing an exception-safe code is not throwing or catching exceptions, but what we should do between "throw" and "capture" to minimize the side effects of throwing exceptions. Examples are as follows:

According to the exception security axiom, Delete does not throw an exception.

No recommended way Recommended Way

void Button::setaction (const Action *newaction)

{

Delete action_;//change State first

Action_=newaction->clone (); Then do it, but it may throw an exception, and the button's state has changed, damaging the button's state

}

void Button::setaction (const Action *newaction)

{

Action *temp=newaction->clone (); First of all, if there is an exception, it will stop execution, but the button's status has not changed

Delete action_;//and then change the state

Action_=temp;

}


So here's a suggested rule: do anything that might throw an exception (but not change the important state of the object), and then use the end of the operation that doesn't throw an exception.

It is important to mention that writing the correct exception handling code rarely uses a try statement. Use a try statement block as little as possible. Use them mainly in these places: You do want to check the type of exception that is passed in order to do something to him. In practice, these places are usually between code and third party libraries, and between code and the operating system at the module decomposition.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.