どのようなクラスがスマートポインタ(Boolan)に適していないか

6018 ワード

私はルールに従うのが一番好きではありません.ノートを書かせて、先生のpptに従って写すのはどういう意味ですか.だから私はやはり自分のものを書くのが好きです.
最近私は変な癖があって、すべてのポインタ付きクラスをスマートポインタを使って資源の分配と回収を制御するように改造するのが好きです.c++11標準である以上、99標準に代わることができ、より安全で先進的な使い方だと思いますが、なぜ使わないのでしょうか.結局、この2週間、侯捷先生のc++授業の例のスマートポインタの書き換えに苦労し、いつスマートポインタを使うべきか、いつ使うべきではないかを悟った.宿題を提出する日まであと2日しか残っていないので、暇があればDate類、Rectangle類の書き換えもここで話します.
私のここの目的はスマートポインタを説明することではないので、詳しくはありません.
スマートポインタとは
インテリジェントポインタはテンプレートを通じて実現される一般的なポインタのパッケージであり、shared_を好む.ptrポインタ.参照カウントにより、自分の参照数を管理し、カウントが0の場合、メモリを自動的に解放します.
いつ使えばいいですか?
もともと私はAタイプのポインタを持っていました.
A *a = new A();

これでdeleteに行くのを心配します.この行のコードが1つの関数内にあり、aがその関数の戻り値として返される場合(例えば、最初の週のジョブDateクラスがランダムに10の日付で返される関数を生成する場合)は、いつdeleteを選択するかが重要です.時々選択しにくく、メンテナンスの複雑さを増すことがあります.
では、これがスマートポインタが活躍する時です.
shared_ptra = make_shared();

さっきの文と同じ効果を発揮しました.もしこの関数が
shared_ptrfun() {
shared_ptra = make_shared();
//aに かする
return a;
}

このようにすると、関数にはaが定義され、参照カウントは1であり、aを返し、aの参照カウントは依然として1である.一方、aの使用が完了すると、関数の使用時に存在する役割ドメインの終了位置になる.aの参照カウントは-1になり、このとき0になり、メモリが自動的に解放されます.私たちが人工deleteする必要はありません.
Stringクラスはsharedを使用しない
このString類は私が自分で書いたものですが、授業とは少しだけ違います.メンバーを返す関数の戻りタイプはconst char*に設定します.これにより、関数を使用するときにメンバーに望ましくない変更を加えることを避けることができます.

#ifndef STRING_H
#define STRING_H

#include 
#include 
using std::ostream;

class String {
public:
    String(const char *cstr = 0);
    String(const String&);
    String &operator=(const String&);
    ~String();
    const char* get() const;
private:
    char *m_data;
};

inline
String::String(const char *cstr) {
    if (cstr) {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data, cstr);
    } else {
        m_data = new char[1];
        *m_data = '\0';
    }
}

inline
String::String(const String &str) {
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
}

inline
String& String::operator=(const String &right) {
    if (this == &right) return *this;

    delete[] m_data;
    m_data = new char[strlen(right.m_data) + 1];
    strcpy(m_data, right.m_data);

    return *this;
}

inline
String::~String() {
    delete[] m_data;
}

inline
const char* String::get() const {  //         const
    return m_data;
}

inline
ostream& operator<

これは使用後(見るに忍びない、走れない):
#ifndef STRING_H
#define STRING_H

#include 
#include 
#include 
using std::ostream;
using std::shared_ptr;
using std::make_shared;

class String {
public:
    String(const char *cstr = 0);
    String(const String&);
    String &operator=(const String&);
    ~String();
    const char* get() const;
private:
    shared_ptr m_data;
};

inline
String::String(const char *cstr) {
    char* pstr; 
    if (cstr) {
        pstr = new char[strlen(cstr) + 1];
        strcpy(pstr, cstr);
    } else {
        pstr = new char[1];
        pstr = '\0';
    }
    m_data = make_shared (pstr, [](char *pstr){ delete[] pstr; });
}

inline
const char* String::get() const {
    return m_data.get();
}

inline
ostream& operator<

ここでは、このプログラムが走れなくなったことを明確に伝えることができます.しかし、ここではスマートポインタの利点を見ることができます.それは、スマートポインタを使用すると、すべてのメンバーがポインタタイプではなく、特殊な操作がなければ、コピー構造、付与演算子の再ロード、解析、3つの関数をデフォルトだけで使用でき、コード量を大幅に減らすことができます.
しかし、このクラスはスマートポインタを使うのに適していません.原因は今はあまり見えないかもしれません.次はDateクラスの書き換えとRectangleクラスの書き換えを出します.これではっきりします.
Date類は同じで、走ることもできませんが、私はやはりここでコードを貼っています.
/*
 *             
 */
const int DATE_SIZE = 10;
/*
 *   10     
 */
unique_ptr CreatePoints() {
    unique_ptr dates(new Date[DATE_SIZE]);
    for (int i = 0; i < DATE_SIZE; ++i) {
        int year = rand() % 1000 + 1500;
        int month = rand() % 12 + 1;
 
        int maxDay = 28;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                maxDay = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                maxDay = 30;
                break;
            case 2:
                if ((year % 4 == 0 && year % 100 != 0)
                        || year % 400 == 0) 
                    maxDay = 29;
                break;
        }
        int day = rand() % maxDay + 1;
 
        dates[i] = Date(year, month, day);
    }
 
    return dates;
}
 
/*
 *                  
 */
unique_ptr Sort(unique_ptr &dates) {
    sort(&dates[0], &(dates[DATE_SIZE - 1]) + 1);
    return dates;
}

この2つの共通点は,スマートポインタに改造する必要があるのはすべて配列である,すなわち,配列などがスマートポインタにバインドする変数に依存したり順序関係がある場合,スマートポインタを用いるのは賢明ではない,c++primer書でも,できるだけ数組を少なくし,標準ライブラリコンテナを多く用いることである.配列を使わざるを得ない場合は、new、delete管理、または別の方法を使用したほうがいいです.
次のRectangleクラスなど、スマートポインタに適している場合があります.
class Shape {
    int no;
};

class Point {
    int x, y;
public:
    Point() = default;
    Point(const int &x = 0, const int &y = 0):x(x), y(y){}
};

class Rectangle: public Shape {
    int width, height;
    shared_ptr leftUp;
public:
    Rectangle(const int&, const int&, const int&, const int&);
    //       ,  ,  ,        
};

inline
Rectangle::Rectangle(const int &w, const int &h, const int &x, const int &y):leftUp(make_shared(x, y)), width(w), height(h){}


これにより,メンバーが単一のオブジェクトである場合にスマートポインタに変更するのは快適であり,Rectangleクラスのコピー,付与,プロファイルはすべて省け,メモリの解放の心配もない.
これはただ私がここ数日c++を勉强してからの考えで、必ずしも正しいとは限らない.后で功力が深くなったら、私自身が今の考えを覆すかもしれない.だから何か疑問があったら、次のようにメッセージを残して、私たちの思想が知恵の火の光にぶつかって、共に進歩することを望んでいます.