⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 5resource.html

📁 Visual C++ has been one of most effective tool for the large industrial applications. This book is t
💻 HTML
📖 第 1 页 / 共 5 页
字号:
{
public:
    AssignNode (auto_ptr<Node> & pLeft, auto_ptr<Node> & pRight)
        : BinNode (pLeft, pRight)
    {}

    double Calc () const;
};</pre>
    </td></tr>
</table>
<!-- End Code -->
<p>As before, we were able to get rid of explicit destructors. 
<p>We can continue our destructor derby with the <var>Parser</var> itself. It can own its parsing tree through an <var>auto_ptr</var> and gone is its explicit destructor.
<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>    auto_ptr&lt;Node&gt;    _pTree;</pre>
    </td></tr>
</table>
<!-- End Code -->
<p>We can't get rid of the destructor of <var>MultiNode</var> yet. For the time being, let's just rewrite it so that it accepts <var>auto_ptr</var>s as arguments to its methods. We'll return to the issue "owning containers" later.


<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>class MultiNode: public Node
{
public:
    MultiNode (auto_ptr&lt;Node&gt; &amp; pNode)
    {
        AddChild (pNode, true);
    }
    ~MultiNode ();
    void AddChild (auto_ptr&lt;Node&gt; &amp; pNode, bool isPositive)
    {
        _aChild.push_back (pNode.release ());
        _aIsPositive.push_back (isPositive);
    }
protected: 
    std::vector&lt;Node*&gt; _aChild;
    std::vector&lt;bool&gt;  _aIsPositive;
};</pre>
    </td></tr>
</table>
<!-- End Code -->

<p>And now let's look at the <var>Parser::Expr</var> method after it's been generously sprinkled with <var>auto_ptr</var>s.

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre><font color="red">auto_ptr&lt;Node&gt;</font> Parser::Expr ()
{
    // Parse a term
    <font color="red">auto_ptr&lt;Node&gt;</font> pNode = Term ();
    if (pNode.<font color="red">get ()</font> == 0)
        return pNode;

    EToken token = _scanner.Token ();
    if (token == tPlus || token == tMinus)
    {
        // Expr := Term { ('+' | '-') Term }
        <font color="red">auto_ptr&lt;MultiNode&gt;</font> pMultiNode (new SumNode (pNode));
        do
        {
            _scanner.Accept ();
            <font color="red">auto_ptr&lt;Node&gt;</font> pRight = Term ();
            pMultiNode->AddChild (pRight, (token == tPlus));
            token = _scanner.Token ();
        } while (token == tPlus || token == tMinus);
        // with member template support
        pNode = pMultiNode; // &lt;- Up-casting!
        // pNode = <font color="red">up_cast&lt;Node&gt;</font> (pMultiNode);
    }
    else if (token == tAssign)
    {
        _scanner.Accept ();
        // Expr := Term = Expr
        <font color="red">auto_ptr&lt;Node&gt;</font> pRight = Expr ();
        // provided the Term is an lvalue
        if (pNode->IsLvalue ())
        {
            // Assignment node
            pNode = <font color="red">auto_ptr&lt;Node&gt;</font> (new AssignNode (pNode, pRight));
        }
        else
        {
            _status = stError;
            pNode = Expr ();
        }
    }
    // otherwise Expr := Term
    return pNode;
}</pre>
    </td></tr>
</table>
<!-- End Code -->

<p>There is one tricky point in this code that requires some explaining. We are dealing with two types of <var>auto_ptr</var>s--one encapsulating a <var>Node</var> and another encapsulating a <var>MultiNode</var> (only <var>MultiNode</var> has the <var>AddChild</var> method). At some point, when we are done adding children, we must convert a pointer to <var>MultiNode</var> to a pointer to <var>Node</var>. With pointers it was no trouble, because a <var>MultiNode</var> "is-a" <var>Node</var> (they are related through inheritance). But <var>auto_ptr&lt;Node&gt;</var> is a totally different class from <var>auto_ptr&lt;MultiNode&gt;</var>. So this simple line of code:

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>pNode = pMultiNode; // &lt;- Up-casting!</pre>
    </td></tr>
</table>
<!-- End Code -->

hides some pretty interesting stuff. In fact, there is a special mechanism called <b><i>member template</i></b> that's used inside the <var>auto_ptr</var> to make possible this types of conversions (called up-casting, because they cast the pointer up the class hierarchy).
<p>Look a the following code--a transfer constructor and an assignment operator override are added to the <var>auto_ptr</var> template.

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>template&lt;class T&gt;
class auto_ptr
{
public:
    ...
    // "transfer" from derived class
    template&lt;class U&gt; 
    auto_ptr (auto_ptr&lt;U&gt; &amp; pSrc)
    {
        _p = pSrc.release ();
    }

    // assignment of derived class
    template&lt;class U&gt; 
    auto_ptr & operator= (auto_ptr&lt;U&gt; &amp; pSrc)
    {
        if (this != &amp;pSrc)
            _p = pSrc.release ();
        return *this;
    }
};</pre>
    </td></tr>
</table>
<!-- End Code -->

These new methods are templates themselves. They are parametrized by another type, <var>U</var>.

<p>The new transfer constructor can be used to construct an <var>auto_ptr</var> of one type, parametrized by <var>T</var>, from an <var>auto_ptr</var> of another type, parametrized by <var>U</var>. So, in fact, this constructor is a template parametrized by two types, <var>T</var> and <var>U</var>. 
<p>The new overload of the assignment operator can accept an <var>auto_ptr</var> parametrized by an arbitrary type <var>U</var>. It's this override that's invoked in the statement:
<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>pNode = pMultiNode; // &lt;- Up-casting from MultiNode to Node</pre>
    </td></tr>
</table>
<!-- End Code -->

Here, <var>pNode</var> is of the type <var>auto_ptr&lt;Node&gt;</var> and <var>pMultiNode</var> is of the type <var>auto_ptr&lt;MultiNode&gt;</var>. The compiler will automatically try to instantiate the appropriate implementation of the method <var>auto_ptr&ltNode&gt;::operator= (auto_ptr&lt;MultiNode&gt; &amp)</var>. And here's where type safety kicks in. When the compiler generates the line from the template:

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>_p = pSrc.release ();</pre>
    </td></tr>
</table>
<!-- End Code -->
it has to assign a pointer to <var>MultiNode</var> returned from <var>pSrc.release ()</var>, to a pointer to <var>Node</var>, <var>_p</var>. The conversion works because of the is-a relationhip between the two classes. Had we tried the opposite conversion:

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>pMultiNode = pNode; // &lt;- Error! Down-casting</pre>
    </td></tr>
</table>
<!-- End Code -->

the compiler would generate an error, because it would fail in the conversion of <var>Node *</var> to <var>MultiNode *</var> during the instantiation of the appropriate template.

<p>The bottom line is that the assignment of <var>auto_ptr</var>s will only work for those types for which the assignments of pointers works. Notice that the types don't have to be related by inheritance. You can, for instance, implicitly convert a pointer to <var>Node</var> to a <var>void</var> pointer. It follows than that you can convert <var>auto_ptr&ltNode&gt;</var> to <var>auto_ptr&lt;void&gt;</var>.
<!-- Sidebar -->
<table width="100%" border=0 cellpadding=5><tr>
<td width=10>&nbsp;</td>
<td bgcolor="#cccccc" class=sidebar>
If your compiler doesn't support member templates, don't despair! I have a workaround for you. Since you won't be able to do implicit <var>auto_ptr</var> conversion, you'll have to do it explicitly.
<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>pNode = <font color="red">up_cast&lt;Node&gt;</font> (pMultiNode);</pre>
    </td></tr>
</table>
<!-- End Code -->

I created the <var>up_cast</var> function template, parametrized by two types, <var>To</var> and <var>From</var>.

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>template&lt;class To, class From&gt;
auto_ptr&lt;To&gt; <b>up_cast</b> (auto_ptr&lt;From&gt; & from)
{
    return auto_ptr&lt;To&gt; (from.release ());
}</pre>
    </td></tr>
</table>
<!-- End Code -->

Notice that, when I invoke this template, I don't have to specify the second type, <var>From</var>. The compiler can figure it out by looking at the type of the argument (<var>pMultiNode</var>, in this case). As before, the type checking is done by the compiler when instantiating this template for the requested pair of types.

</td></table>
<!-- End Sidebar -->

<p>It's pretty straightforward to convert the rest of the <var>Parser</var> to use <var>auto_ptr</var>s.

<p class=summary>To summarize: Memory resources can be safely kept and transferred from one point to another using <var>auto_ptr</var>s. You can easily transform and existing program to use Resource Management techniques. Just search your project for all calls to <var>new</var> and make sure the resulting pointers are safely tucked inside <var>auto_ptr</var>s.

<h3>Safe Containers</h3>

<p>We are not done yet. There are still some parts of our program that are not 100% resource safe. Let's go back to one such place inside the class <var>MultiNode</var>.

<!-- Code -->
<table width="100%" cellspacing=10><tr>
    <td class=codeTable>
<pre>class MultiNode: public Node
{
public:
    MultiNode (auto_ptr&lt;Node&gt; &amp; pNode)
    {
        AddChild (pNode, true);
    }
    ~MultiNode ();
    void AddChild (auto_ptr&lt;Node&gt; &amp; pNode, bool isPositive)
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -