Qtスマートポインタ--QScopedPointer
3167 ワード
文書ディレクトリ概要 QScopedPointer const制限 は、1つのケース を考慮する. QScopedArrayPointer
概要
前の文章ではQpointerの使い方を詳しく紹介しましたが、ここではQtのもう一つのスマートポインタQScopedPointerの使い方をまとめ続けます.
QScopedPointerとC++のスマートポインタstd::unique_ptrは、newオペレータがスタックに割り当てたダイナミックオブジェクトをパッケージ化し、ダイナミックに作成されたオブジェクトがいつでも正しく削除されることを保証します.しかし、より厳格な所有権を持ち、譲渡できません.オブジェクトの管理権を取得すると、そこから取り戻すことはできません.すなわち,役割ドメインが出るとポインタは自動的に削除される.なぜなら,そのコピー構造と付与操作はすべてプライベートであり,QObjectとその派生クラススタイルと同じであるからである.
QScopedPointer
まず、公式の例を見てみましょう.
スマートポインタが使用されていません:
上記の書き方は、ちょっとした不注意でメモリが漏れることがありますが、スマートポインタを使うと簡単になります.
注:コピー構造と付与操作はプライベートなので、コンテナの要素として使用できません.
const制限
C++ポインタのconst限定はQScopedPointerで表すこともできます.
一つの状況を考える
QScopedPointerスマートポインタを使用して動的に作成されたオブジェクトは、役割ドメインが出ると自動的に解放され、空になりますが、関数の戻り値が必要な場合はどうすればいいのでしょうか.
たとえば、次のような場合です.
なお、createLabel()関数でlabelオブジェクトを作成して返す場合は、data()ではなくtake()を使用します.T*QScopedPointer::data()constはオブジェクトへの定数ポインタを返すため、QScopedPointerはオブジェクトの所有権を保持します.したがってdata()で返すと自動的に削除され,mian関数のp 1が野ポインタとなりプログラムがクラッシュする.T*QScopedPointer::take()を使用してもオブジェクトポインタを返しますが、QScopedPointerはオブジェクト所有権を持たず、この関数を呼び出すcallerに移行し、QScopePointerオブジェクトポインタはNULLに設定されます.
もう一つの関数に注意してください.void QScopedPointer::reset(T*other=Q_NULLPTR):deleteが現在指すオブジェクトは、その構造関数を呼び出し、ポインタを別のオブジェクトotherに向け、所有権をotherに移す.
QScopedArrayPointer
対応するもう1つのポインタQScopedArrayPointerは、配列の処理に特化しており、QScopedPointerと同様の使い方をしています.
公式の簡単な例:
役割ドメインを超えるとdelete[]削除ポインタが自動的に呼び出されます.ここでは説明を展開しません.
概要
前の文章ではQpointerの使い方を詳しく紹介しましたが、ここではQtのもう一つのスマートポインタQScopedPointerの使い方をまとめ続けます.
QScopedPointerとC++のスマートポインタstd::unique_ptrは、newオペレータがスタックに割り当てたダイナミックオブジェクトをパッケージ化し、ダイナミックに作成されたオブジェクトがいつでも正しく削除されることを保証します.しかし、より厳格な所有権を持ち、譲渡できません.オブジェクトの管理権を取得すると、そこから取り戻すことはできません.すなわち,役割ドメインが出るとポインタは自動的に削除される.なぜなら,そのコピー構造と付与操作はすべてプライベートであり,QObjectとその派生クラススタイルと同じであるからである.
QScopedPointer
まず、公式の例を見てみましょう.
スマートポインタが使用されていません:
void myFunction(bool useSubClass)
{
MyClass *p = useSubClass ? new MyClass() : new MySubClass;
QIODevice *device = handsOverOwnership();
if (m_value > 3) {
delete p;
delete device;
return;
}
try {
process(device);
}
catch (...) {
delete p;
delete device;
throw;
}
delete p;
delete device;
}
上記の書き方は、ちょっとした不注意でメモリが漏れることがありますが、スマートポインタを使うと簡単になります.
void myFunction(bool useSubClass)
{
QScopedPointer p(useSubClass ? new MyClass() : new MySubClass);
QScopedPointer device(handsOverOwnership());
if (m_value > 3)
return;
process(device);
}
注:コピー構造と付与操作はプライベートなので、コンテナの要素として使用できません.
const制限
C++ポインタのconst限定はQScopedPointerで表すこともできます.
const QWidget *const p = new QWidget();
// :
const QScopedPointer p(new QWidget());
QWidget *const p = new QWidget();
// :
const QScopedPointer p(new QWidget());
const QWidget *p = new QWidget();
// :
QScopedPointer p(new QWidget());
一つの状況を考える
QScopedPointerスマートポインタを使用して動的に作成されたオブジェクトは、役割ドメインが出ると自動的に解放され、空になりますが、関数の戻り値が必要な場合はどうすればいいのでしょうか.
たとえば、次のような場合です.
QLabel * createLabel()
{
QScopedPointer pLabel(new QLabel());
// return pLabel.data(); //invalid
return pLabel.take(); //valid
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QScopedPointer p1(createLabel());
p1->setText("hello");
p1->show();
return a.exec();
}
なお、createLabel()関数でlabelオブジェクトを作成して返す場合は、data()ではなくtake()を使用します.T*QScopedPointer::data()constはオブジェクトへの定数ポインタを返すため、QScopedPointerはオブジェクトの所有権を保持します.したがってdata()で返すと自動的に削除され,mian関数のp 1が野ポインタとなりプログラムがクラッシュする.T*QScopedPointer::take()を使用してもオブジェクトポインタを返しますが、QScopedPointerはオブジェクト所有権を持たず、この関数を呼び出すcallerに移行し、QScopePointerオブジェクトポインタはNULLに設定されます.
もう一つの関数に注意してください.void QScopedPointer::reset(T*other=Q_NULLPTR):deleteが現在指すオブジェクトは、その構造関数を呼び出し、ポインタを別のオブジェクトotherに向け、所有権をotherに移す.
QScopedArrayPointer
対応するもう1つのポインタQScopedArrayPointerは、配列の処理に特化しており、QScopedPointerと同様の使い方をしています.
公式の簡単な例:
void foo()
{
QScopedArrayPointer i(new int[10]);
i[2] = 42;
...
return; // our integer array is now deleted using delete[]
}
役割ドメインを超えるとdelete[]削除ポインタが自動的に呼び出されます.ここでは説明を展開しません.