3

ここでは「コンストラクタとデストラクタ」の下のコードを使用しています

基本的に、私はそれを「クラスへのポインター」(少し下)の下のポインター構造と組み合わせたいと思います。

今これは動作します:

int main () {
   CRectangle * prect;     //l2
   CRectangle rect (3,4);  //l3
   prect = ▭          //l4
   cout << "rect area: " << (*prect).area() << endl;
   return 0;
}

私の質問は、l2-l4を、3行目にrectを作成する必要のないより洗練された方法に置き換えることができるかということです。

4

3 に答える 3

3

@eq- の回答も気に入っていますが、動的メモリ割り当てに加えて、新しい配置を試すこともできます。(私が「試してみてください」と言うとき、これが物事を行う方法であるという意味ではありませんが、これはより多くの考えの材料です. 私はあなたを曲がりくねった小さな通路の迷路に導くつもりはありません.)

char mem[sizeof(CRectangle)] alignas(CRectangle);
CRectangle *prect = new (mem) CRectangle(3, 4); // construct
std::cout
    << "rect area: " << prect->area()
    << std::endl;
prect->~CRectangle();                           // destruct

通常、カスタム アロケータを使用する場合は、placement new を使用します。カスタム アロケーターはさまざまな理由で使用できますが、私の仕事では通常、事前割り当て戦略 (プール アロケーターや厳密なメモリ プロビジョニングを備えた組み込みシステムなど) に使用されます。この場合、配置 new は、自動ストレージ クラスを持つメモリを初期化するために使用されています。元のrectオブジェクトと同様に、コードが範囲外になると、オブジェクトのメモリは無効になります。ただし、CRectangleコンストラクターは、クリーンアップが必要な初期化を実行する場合があるため、メモリがスコープから外れる前に、デストラクターへの明示的な呼び出しが行われます。

ポインターで delete を呼び出すと未定義になるため、auto_ptrfor を使用できないことに注意してください(メモリが動的に作成されていないため)。カスタムのデリータをコンストラクタに渡す場合にprect使用できます。2 番目のテンプレート パラメータでカスタム デリータを渡す場合にshared_ptr使用できます。unique_ptrカスタム デリーターは、コードがスコープ外になったときにスマート ポインターが自動的にクリーンアップの作業を行うように、デストラクターを明示的に呼び出すだけです。

template <typename T>
struct placement_delete {
    void operator () (T *t) const { t->~T(); }
};

char mem2[2][sizeof(CRectangle) alignas(CRectangle);
std::shared_ptr<CRectangle>
    sprect(new (mem2[0]) CRectangle(2, 3), placement_delete<CRectangle>());
std::unique_ptr< CRectangle, placement_delete<CRectangle> >
    uprect(new (mem2[1]) CRectangle(3, 4));

呼び出しによって例外newがスローされる場合があります。std::bad_allocキャッチされていないため、例外がスローされた直後にプログラムが終了し、エラーが発生します。例外を適切に処理したい場合はtry、andcatchブロックを使用します。

CRectangle *prect;
try {
    prect = new (mem) CRectangle(3, 4);
} catch (std::bad_alloc) {
    // do something about it?
    abort();
}

学習のために、abort大丈夫です。例外をキャッチする練習ができますが、 の結果として残されたエラー状態を分析するときに、問題の場所をすばやく特定できますabort。(UNIX では、これは通常、コア ファイルです。)

于 2012-06-04T21:28:59.947 に答える
3

rect自動変数 (上記のコードなど) を必要とせずにオブジェクトを作成するには、new演算子を使用する必要があります。new演算子で作成されたオブジェクトはfree storeに格納され、new式は新しく作成されたオブジェクトへのポインターに評価されます。

さて、new演算子が答えであり、それだけであると言うことができますが、実際にはそうではありません。これらの数行をより洗練されたソリューションに置き換えるという質問には答えません。

この回答の残りの部分は、どのようnewに使用できるかの接線になります。

自動オブジェクトとは異なり、フリー ストアに格納されたオブジェクトは自動的に破棄されませんが、その寿命と破棄はdeleteオペレーターによって制御されます (リソースを解放するために不要になったオブジェクトを削除する必要があります)。確実に破棄するには、常に式からスマート ポインターnewと呼ばれるものにポインターを格納する必要があります。単純な良いルール:スマート ポインター コンストラクター内でのみ演算子を使用します (自分が何をしているのかを理解していない場合)。new

C++11 にはいくつかのスマート ポインターがありますが、以前のバージョンの標準ではauto_ptr. おそらく、その癖のためか、単に代替品を入手したため、実際には C++11 で廃止されており、少なくとも C++11 では、おそらく新しいコードで使用するべきではありません (現在、これは意見です)。 .

スマート ポインターの使用例:

boost::shared_ptr<CRectangle> shared_rect(new CRectange(3, 4));
std::unique_ptr<CRectangle> rect(new CRectangle(3, 4)); // C++11 only

// use smart pointers like like regular pointers; indirection through * or ->
// i.e. (*rect).area() or rect->area()
于 2012-06-04T20:35:29.723 に答える
0

じゃあこれはどう?

int main () {
   CRectangle rect (3,4); // on stack
   cout << "rect area: " << rect.area() << endl;
   return 0;
}

またはあなたが持っている必要prectがある場合:

int main () {
   CRectangle rect (3,4); // still on stack
   CRectangle * prect = &rect; // simple alias
   cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
   return 0;
}

しかし、少なくともあなたの単純なコードprectでは冗長です。

通常、作成時またはそれ以降に割り当てられた一部 (またはヒープに割り当てられたnew CRectangle()から派生したクラス)が表示されることが予想されます。しかし、あなたが何をしようとしているのかはあまり明確ではありません。しかし、あなたの例では単に のエイリアスであるため、直接使用しないのはなぜですか (私の最初のコード)?CRectangleprectprectrectrect


ヒープの使用:

int main () {
   CRectangle* prect = new CRectangle(3,4); // using heap
   // new will throw if out of memory, so no check for null pointer needed here
   cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
   delete prect; // free the memory - needed because it's not a stack object
   return 0;
}

Mooing Duck がコメントで述べたように、STL は(C++11 で) にstd::auto_ptr取って代わられました。std::unique_ptrこの「スマート ポインター」は、ヒープ上にあるクラスのポインターのスタック上のコンテナー クラスとして機能するため、クリーンアップも行います。

int main () {
   try
   {
     std::auto_ptr<CRectangle> prect(new CRectangle(3,4)); // using heap, via smart ptr
     // new will throw if out of memory, so no check for null pointer needed here
     cout << "rect area: " << prect->area() << endl; // same as (*prect).area()
   }
   catch(exception& e)
   {
     cout << "Exception caught: " << e.what() << endl;
   }
   return 0;
}

との主な違いはauto_ptrunique_ptr所有権に関するセマンティクスです。ウィキペディアのSmart Pointersページで概要を確認できます。

于 2012-06-04T20:25:31.757 に答える