Effective use and design of the COM smart pointer-Clause 17: The heavy-duty operator shall comply with the C/C ++ Convention

Source: Internet
Author: User
Clause 17: overloaded operators should comply with C/C ++ for more terms, please go to the original Article Source: http://blog.csdn.net/liuchang5

Suppose we use a third-party stack template class, and its pop function is like this:

template<class T> void Stack<T>::Pop( T& result ){  if( vused_ == 0)  {    throw "pop from empty stack";     }  else  {    result = v_[--vused_];  }}

Unfortunately, this function is not from the master's hand. Is it abnormal? The condition is that the assignment operator of the T type should abide by the C/C ++ conventions without throwing an exception. Imagine if the value assignment operator throws an exception, the vused in the stack has been reduced, but the operation has not been completed. In this case, the object status is inconsistent [13 ].

However, this function is indeed understandable. Its exception security is based on the C/C ++ convention. If your T type throws an exception for the value assignment operator, you should be responsible for it-because you have violated the conventions.

C/C ++: do not let the assignment operator throw an exception, and C ++ uses the default value assignment operation. If we write a smart pointer, it should be like this:

Mysmartptr <t> & mysmartptr: Operator = (const mysmartptr <t> & mysmartptr) {... // several operations, but no exception should be thrown}

If it does not throw an exception, it complies with the C/C ++ conventions. But what if he throws an exception accidentally or the function called at the lower level throws an exception? The above stack template class is reduced to an abnormal and insecure situation.

Obviously, he is not very popular, so we may make some improvements to him. Add a throw () keyword to him to ensure that he does not throw an exception. But that may not be enough, because it simply terminates the program and we hope to promptly handle the exception so as to detect the error in time. The improved solution is as follows:

Mysmartptr <t> & mysmartptr: Operator = (const mysmartptr <t> & mysmartptr) Throw () {try {... // several operations, but no exception should be thrown} catch (...) {... STD: Abort ();} return * This ;}

However, we will find that ccomptr made a general action while doing this. Let's look at its function declaration:

T* operator=(_In_ const CComPtr<T>& lp) throw()

It violates the C/C ++ conventions again! Because it does not return a reference of its own type! The original intention of ccomptr is to make the smart pointer more like a pointer. You may say that there is no harm. However, the following code may make your program behave as expected, but in some "unfortunate circumstances" The program crashes:

Func (iunknown * piunknown) {ccomptr spiunknown = NULL; m_pi = spiunknown = piunknown; // This syntax is dosomething () recognized by C/C ++ ();} // later, the member attribute m_pi may be called elsewhere.

You may ask, "What is an unfortunate situation '?". Assume that m_pi is an interface pointer. The reference count is increased once less, and the program may crash. If m_pi is a smart pointer, you are lucky.

To solve this problem, follow the C/C ++ conventions and change ccomptr to the following statement:

CComPtr<T>& operator=(_In_ const CComPtr<T>& lp) throw()

Hmm ~ The problem is solved. Let's look at _ com_ptr_t, which is not honest here. Although the type he returns is a reference of this type, he may throw an exception due to interface query failure. Fortunately, he adds the thorw () keyword to the value assignment operator, which may cause the program to crash and prevent you from getting into the trouble of exception and insecurity. His statement is as follows:

    _com_ptr_t& operator=(const _com_ptr_t& cp) throw()

Finally, let's go back to the beginning and provide a version that causes the stack to remain exceptionally secure without complying with the conventions. This version comes from exceptional C ++. Maybe it doesn't guide us to better write a general smart pointer. However, it can give us some inspiration on the exception security issue-the exception throw object state should not be changed:

template<class T> void Stack<T>::Pop( T& result ){  if( vused_ == 0)  {    throw "pop from empty stack";  }  else  {    result = v_[vused_-1];    --vused_;  }}

Finally, remember that it is worthwhile to make the value assignment operator conform to the language conventions, so that it can make your smart pointer less misused. Even if your code has some side effects following the language conventions, we can think that these side effects are produced by the language. In fact, C/C ++ is not perfect.

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.