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?\n>> ";
    cin >> name;

    cout << name << ", please enter up to " << ArSize << " short sayings <empty line to quit>:\n";
    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() != ‘\n‘)
            continue;
        if (!cin || temp[0] == ‘\0‘)
            break;
        else
            sayings[i] = temp;
    }
    int total = i;

    if (total > 0)
    {
        cout << "Here are your sayings:\n";
        for (i = 0; i < total; i++)
            cout << sayings[i] << "\n";

        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:\n" << * shortest << endl;
        cout << "First alphabetically:\n" << * first << endl;
        srand(time(0));
        int choice = rand() % total;
        String * favorite = new String(sayings[choice]);
        cout << "My favorite saying:\n" << *favorite << endl;
        delete favorite;
    }
    else
        cout << "Not much to say, eh?\n";
    cout << "Bye.\n";
    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\n";
    }
    ~JustTesting()
    {
        cout << words << " destroyed\n";
    }
    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:\n" << "buffer: " << (void *) buffer << "    heap: " << pc2 << endl;
    cout << "Memory contents:\n";
    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:\n";
    cout << pc3 << ": ";
    pc3->Show();
    cout << pc4 << ": ";
    pc4->Show();

    delete pc2;
    delete pc4;
    delete [] buffer;
    cout << "Done\n";
    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\n";
    }
    ~JustTesting()
    {
        cout << words << " destroyed\n";
    }
    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:\n" << "buffer: " << (void *) buffer << "    heap: " << pc2 << endl;
    cout << "Memory contents:\n";
    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:\n";
    cout << pc3 << ": ";
    pc3->Show();
    cout << pc4 << ": ";
    pc4->Show();

    delete pc2;
    delete pc4;
    delete [] buffer;
    cout << "Done\n";
    return 0;
}


Cpp Chapter 12: Classes and Dynamic Memory Allocation Part2

原文地址:https://www.cnblogs.com/fsbblogs/p/9801042.html

时间: 2024-10-03 22:25:11

Cpp Chapter 12: Classes and Dynamic Memory Allocation Part2的相关文章

Cpp Chapter 12: Classes and Dynamic Memory Allocation Part1

12.1 Dynamic memory and classes 12.1.1 A review example and static class members Now try implement a String class(a flawed one): // strngbad.h -- flawed string class definition #include <iostream> #ifndef STRNGBAD_H_INCLUDED #define STRNGBAD_H_INCLU

[Paper翻译]Scalable Lock-Free Dynamic Memory Allocation

原文: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.87.3870&rep=rep1&type=pdf Abstract 动态内存分配器(malloc/free)在多线程环境下依靠互斥锁来保护共享数据的一致性.使用锁在性能,可用性,健壮性,程序灵活性方面有很多缺点.Lock-free的内存分配器能消除线程延迟或被杀死以及CPU的调度策略对程序的性能影响.这篇paper呈上了一个完整的无锁内存分配器.它的实现只使用被广泛支

C++ storage allocation + Dynamic memory allocation + setting limits + initializer list (1)

1. 对象的空间在括号开始就已经分配,但是构造在定义对象的时候才会实现,若跳过(譬如goto),到括号结束析构会发生错误,编译会通不过. 2.初始化 1 struct X { int i ; float f; char c;}; 2 3 - X x1 = { 1,2.2,'c'}; 4 X x2[3] = { {1,1.1,'a'},{2,2.2,'b'} }; 5 6 7 struct Y {float f; int i; Y(int a);} ; 8 9 Y y1[] = {Y(1),Y(2

A Reusable Aspect for Memory Allocation Checking

The checking logic would be refactored into an aspect file, as follows: after(void * s) : (call($ malloc(...)) || call($ calloc(...)) || call($ realloc(...))) && result(s) { char * result = (char *)(s); if (result == NULL) { /* routine to handle t

Cpp Chapter 9: Memory Models and Namespaces Part2

9.2.4 Static duration, external linkage ) External variables External variables are defined outside, thus external to any function.It is also termed global variables, which could be accessed in any function that follow's the external variable's defin

Cpp Chapter 10: Objects and Classes Part2

10.2.4 Using classes Following exapmle uses the class definition and implementation written in previous files: // usestok0.cpp -- the client program // compiler with stock00.cpp #include <iostream> #include "stock00.h" int main() { Stock s

Cpp Chapter 11: Working with Classes Part2

11.5.3 An implementation comment ) The separation of interface from implementation is one of the goals of OOP. ) Example of the implementation of the class Vector in a rand walk simulation: // randwalk.cpp -- using the Vector class // compile with th

Cpp Chapter 13: Class Inheritance Part1

class inheritance lets you derive new classes from old ones, inheriting its properties of the old class, called the base class With inheritance, you can: 1 add functionality to existing classes 2 add the data a class represents 3 modify how a class m

c++ Dynamic Memory

1. make_shared<T>(args): return a shared_ptr dynamically allocated object of type T. Use args to initialize the object. shared_ptr<T> p(q): p is a copy of shared_ptr q. Increase the count in q. The pointer in q must be convertable to T. p = q: