Qtでスマートポインターを使用する機能

スマートポインターは、オブジェクトの有効期間を管理するための非常に重要なメカニズムです。 Qtには、オブジェクトがQObject基本クラスから継承され、「関係」が設定されている場合(親/子)に、オブジェクトの存続期間を管理するためのモデルがあります。 オブジェクトを削除すると、その子もすべて削除されます。 オブジェクトの存続期間を管理するこのモデルは、オブジェクト間の相互作用のテクノロジー「Signals&Slots」と非常によく組み合わされ、スマートポインターを使用すると、デバッグが困難なバグが発生する可能性があります。



この記事では、QSharedPointerの「ライト」バージョンであるスマートポインターQScopedPointerについて説明します。 バージョン4.6で導入されたQScopedPointer。



ブーストでは、Qt-smartスマートポインターに類似しています:

QSharedPointer-ブースト:: shared_ptr

QWeakPointer-ブースト:: weak_ptr

QScopedPointer-ブースト:: scoped_ptr



例1


m_socketオブジェクトを削除せず、したがってアプリケーションが終了してもソケットは切断されない単純なプログラム:



class test_socket : public QTcpSocket { public: test_socket( QObject * parent ) : QTcpSocket( parent ) { } virtual ~test_socket( ) { qDebug( ) << "~test_socket"; } }; class test_scop_ptr_obj : public QObject { Q_OBJECT test_socket * m_socket; public: test_scop_ptr_obj( ) : m_socket( new test_socket( 0 ) ) { m_socket->connectToHost( "www.ru", 80 ); connect( m_socket, SIGNAL( stateChanged ( QAbstractSocket::SocketState ) ), SLOT( on_state_changed( QAbstractSocket::SocketState ) ) ); } virtual ~test_scop_ptr_obj( ) { qDebug( ) << "~test_scop_ptr_obj"; } private Q_SLOTS: void on_state_changed( QAbstractSocket::SocketState socket_state ) { qDebug( ) << socket_state; } }; int main( int argc, char** argv ) { QCoreApplication a( argc, argv ); test_scop_ptr_obj obj; QTimer::singleShot( 3000, &a, SLOT( quit( ) ) ); return a.exec( ); }
      
      





プログラムを開始すると、次の出力が得られます。

QAbstractSocket :: ConnectingState

QAbstractSocket :: ConnectedState

〜test_scop_ptr_obj



例2


次に、行を変更します。



  : m_socket( new test_socket( 0 ) )
      
      







行ごと:



  : m_socket( new test_socket( this ) )
      
      







そして結論を​​得る:



QAbstractSocket :: ConnectingState

QAbstractSocket :: ConnectedState

〜test_scop_ptr_obj

〜test_socket



例3


スマートポインターを追加すると、クラスtest_scop_ptr_objは次のようになります。



 class test_scop_ptr_obj : public QObject { Q_OBJECT QScopedPointer< test_socket > m_socket; public: test_scop_ptr_obj( ) : m_socket( new test_socket( 0 ) ) { m_socket->connectToHost( "www.ru", 80 ); connect( m_socket.data( ), SIGNAL( stateChanged ( QAbstractSocket::SocketState ) ), SLOT( on_state_changed( QAbstractSocket::SocketState ) ) ); } virtual ~test_scop_ptr_obj( ) { qDebug( ) << "~test_scop_ptr_obj"; } private Q_SLOTS: void on_state_changed( QAbstractSocket::SocketState socket_state ) { qDebug( ) << socket_state; } };
      
      







結論が得られます。

QAbstractSocket :: ConnectingState

QAbstractSocket :: ConnectedState

〜test_scop_ptr_obj

〜test_socket

QAbstractSocket :: UnconnectedState



分析


この例ではメモリリークが発生するため、例1は興味深いものではありません。

例2と3は、以前に割り当てられたメモリを解放する技術が異なります。 どちらの例でも、test_socketクラスのオブジェクトは削除されますが、3番目の例では、〜test_scop_ptr_objデストラクターが呼び出された後にon_state_changed関数が呼び出されますが、これはエラーです。 子を削除する前に、親オブジェクトは信号とスロットを切断します。したがって、例2では、​​stateChanged信号はtest_scop_ptr_objオブジェクトに到達しません。



まとめ


例3のエラーを修正するには、削除されたオブジェクトのシグナルの切断をtest_scop_ptr_objデストラクタに追加する必要があります。



  virtual ~test_scop_ptr_obj( ) { m_socket->disconnect( ); qDebug( ) << "~test_scop_ptr_obj"; }
      
      







この場合、出力は例2と同じになります。



All Articles