• Cpp Chapter 12: Classes and Dynamic Memory Allocation Part2


    12.3 Things to remember when using new in constructors

    ) If you use new in constructors, use delete in destructor. Their use should be compatible, pair new with delete and new [] with delete []
    ) Multiple constructors should share the same way of new -- whether all [] or all without [] (for there is only one destructor)
    ) Define a copy constructor that initializes an object to another by doing deep copy
    ) Define an assignment operator that copies one object to another by doing deep copy( check for self-assignment, free previous memory, deep copy, return reference to invoking object)

    Suppose you have code like this, which uses the String class and the standard string class:

    class Magazine
    {
    private:
        String title;
        string publisher;
    ...
    };
    

    Do you need a copy constructor and a assignment operator for the Magazine class? No, because the default copy constructor will do memberwise copy, which uses the copy constructor of class String and string separately, so it is indeed a deep copy.
    If the class involves pre-defined class objects and other members which need deep copy, you might have to access the copy constructor in String and string class explicitly


    12.4 Observations about returning objects

    ) returning a reference to a const object

    const Vector & Max(const Vector & v1, const Vector & v2)
    {
        if (v1.magval() > v2.magval())
            return v1;
        else
            return v2;
    }
    

    First, returning an object invokes the copy constructor, while returning a reference don't. So it is a bit faster.
    Second, the reference should point to an object that exists during the calling function:

    const int & thing(int a, int b)
    {
        int temp = a+b;
        return temp; // invalid! temp expired after the scope so the reference points to nothing
    }
    

    Third, both v1 and v2 in the upper example is const, so the return type has to be const to match

    ) returning a reference to a non-const object
    Two uses: overloading the assignment operator and overloading the << operator for chained output with cout

    s3 = s2 = s1
    

    in chained assignment, "s3 = s2 = s1" is same as "s3 = s2.operator=(s1)", so the assignment operator function modifies s2 and returns it, thus leaving it non-const

    ) return an object
    If the object being returned is local to the called function, then return the object. overloaded arithmetic operators fall into this category.

    To sum up,

    chart const non-const
    reference higher efficiency, input arguments all const overloading assignment operator/overload << operator
    object to avoid certain misuse return local objects, which are defined inside methods

    12.5 Using pointers to objects

    Sample code:

    // saying2.cpp -- using pointers to objects
    // compile with string1.cpp
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include "string1.h"
    const int ArSize = 10;
    const int MaxLen = 81;
    int main()
    {
        using namespace std;
        String name;
        cout << "Hi, what's your name?
    >> ";
        cin >> name;
    
        cout << name << ", please enter up to " << ArSize << " short sayings <empty line to quit>:
    ";
        String sayings[ArSize];
        char temp[MaxLen];
        int i;
        for (i = 0; i < ArSize; i++)
        {
            cout << i+1 << ": ";
            cin.get(temp, MaxLen);
            while (cin && cin.get() != '
    ')
                continue;
            if (!cin || temp[0] == '')
                break;
            else
                sayings[i] = temp;
        }
        int total = i;
    
        if (total > 0)
        {
            cout << "Here are your sayings:
    ";
            for (i = 0; i < total; i++)
                cout << sayings[i] << "
    ";
    
            String * shortest = &sayings[0];
            String * first = &sayings[0];
            for (i = 1; i < total; i++)
            {
                if (sayings[i].length() < shortest->length())
                    shortest = &sayings[i];
                if (sayings[i] < *first)
                    first = &sayings[i];
            }
            cout << "Shortest saying:
    " << * shortest << endl;
            cout << "First alphabetically:
    " << * first << endl;
            srand(time(0));
            int choice = rand() % total;
            String * favorite = new String(sayings[choice]);
            cout << "My favorite saying:
    " << *favorite << endl;
            delete favorite;
        }
        else
            cout << "Not much to say, eh?
    ";
        cout << "Bye.
    ";
        return 0;
    }
    

    Noteworthy:
    1 object initialization with new:

    Class_name * pclass = new Class_name(value);
    

    which invokes constructors.
    2 using pointer to object:

    String * shortest = &sayings[i];
    

    Remember that access class's member by pointer uses the "->" opereator:

    if (sayings[i].length() < shortest->length())
    

    ) Destructors are called in following situations:
    1 if an object is an automatic variable, the object's destructor is called when the program exits the block in which the object is defined
    2 if an object is a static variable, its destructor is called when the program terminates
    3 if an object is created by new, its destructor is only called when explicitly delete the object


    12.5.2 looking again at placement new

    // placenew1.cpp -- new, placement new, no delete
    #include <iostream>
    #include <string>
    #include <new>
    using namespace std;
    const int BUF = 512;
    class JustTesting
    {
    private:
        string words;
        int number;
    public:
        JustTesting(const string & s = "Just testing", int n = 0)
        {
            words = s;
            number = n;
            cout << words << " constructed
    ";
        }
        ~JustTesting()
        {
            cout << words << " destroyed
    ";
        }
        void Show() const
        {
            cout << words << ", " << number << endl;
        }
    };
    
    int main()
    {
        char * buffer = new char[BUF];
    
        JustTesting *pc1, *pc2;
    
        pc1 = new (buffer) JustTesting;
        pc2 = new JustTesting("Heap1", 20);
    
        cout << "Memory block addresses:
    " << "buffer: " << (void *) buffer << "    heap: " << pc2 << endl;
        cout << "Memory contents:
    ";
        cout << pc1 << ": ";
        pc1->Show();
        cout << pc2 << ": ";
        pc2->Show();
    
        JustTesting *pc3, *pc4;
        pc3 = new (buffer) JustTesting("Bad Idea", 6);
        pc4 = new JustTesting("Heap2", 10);
    
        cout << "Memory contents:
    ";
        cout << pc3 << ": ";
        pc3->Show();
        cout << pc4 << ": ";
        pc4->Show();
    
        delete pc2;
        delete pc4;
        delete [] buffer;
        cout << "Done
    ";
        return 0;
    }
    

    The program using placement new has 2 problems:
    1 creating a second object will rewrite the first one in the buffer
    solution:

    pc1 = new (buffer) JustTesting;
    pc3 = new (buffer + sizeof(JustTesting)) JustTesting("Better Idea", 6);
    

    2 freeing the buffer by "delete [] buffer" doesn't call the destructor of the objects containing
    solution: call the destructors explicitly

    pc3->~JustTesting();
    pc1->~JustTesting();
    

    Revised code:

    // placenew1.cpp -- new, placement new, no delete
    #include <iostream>
    #include <string>
    #include <new>
    using namespace std;
    const int BUF = 512;
    class JustTesting
    {
    private:
        string words;
        int number;
    public:
        JustTesting(const string & s = "Just testing", int n = 0)
        {
            words = s;
            number = n;
            cout << words << " constructed
    ";
        }
        ~JustTesting()
        {
            cout << words << " destroyed
    ";
        }
        void Show() const
        {
            cout << words << ", " << number << endl;
        }
    };
    
    int main()
    {
        char * buffer = new char[BUF];
    
        JustTesting *pc1, *pc2;
    
        pc1 = new (buffer) JustTesting;
        pc2 = new JustTesting("Heap1", 20);
    
        cout << "Memory block addresses:
    " << "buffer: " << (void *) buffer << "    heap: " << pc2 << endl;
        cout << "Memory contents:
    ";
        cout << pc1 << ": ";
        pc1->Show();
        cout << pc2 << ": ";
        pc2->Show();
    
        JustTesting *pc3, *pc4;
        pc3 = new (buffer) JustTesting("Bad Idea", 6);
        pc4 = new JustTesting("Heap2", 10);
    
        cout << "Memory contents:
    ";
        cout << pc3 << ": ";
        pc3->Show();
        cout << pc4 << ": ";
        pc4->Show();
    
        delete pc2;
        delete pc4;
        delete [] buffer;
        cout << "Done
    ";
        return 0;
    }
    

  • 相关阅读:
    386. Lexicographical Numbers 输出1到n之间按lexico排列的数字序列
    287. Find the Duplicate Number 找出数组中的重复数字
    165. Compare Version Numbers比较版本号的大小
    java之spring mvc之文件上传
    java之spring mvc之Restful风格开发及相关的配置
    java之spring mvc之页面跳转
    java之spring mvc之数据处理
    java之spring mvc之Controller配置的几种方式
    java之spring mvc之helloworld
    java之spring mvc之初始spring mvc
  • 原文地址:https://www.cnblogs.com/fsbblogs/p/9801042.html
Copyright © 2020-2023  润新知