読者です 読者をやめる 読者になる 読者になる

vectorとunique_ptr その3

vectorはコピーを使う、だからauto_ptrとおなじくunique_ptrは使えない。
以下のコードはコンパイルエラーが発生する。

  vector<unique_ptr<C> > v;
  v.push_back( unique_ptr<C>( new C ) );

まれに、このコードをおすすめするHPが見られるが、コンパイルできるコンパイラーがあるのだろうか?
コンパイルできたとしても、今まで見てきたように、sortなどで副作用が出るので行うべきではない。
C++11対応のコンパイラーであれば、push_backの代わりにemplace_backが使えるかもしれないが、セットは可能でも、やはりsortで問題が発生する。

対処方法はやはりshared_ptrに置き換えればよい。

  vector< shared_ptr<C> > v;
  v.push_back( shared_ptr<C>( new C ) );

shared_ptrのコストを避けようとするのであれば、削除に備える必要がある。

typedef std::vector<unique_ptr<C> > Vip;
typedef std::vector<unique_ptr<C> >::iterator Vip_itr;
typedef std::vector<unique_ptr<C> >::const_iterator Vip_citr;
class D
{
    void _clear( Vip_itr iSt, Vip_itr iEd )
    {
      for( ; iSt < iEd; ++iSt )
      {
        if( *iSt ) delete *iSt;
      }
    }
    void _copy( Vip &dst, Vip_citr iSt, Vip_citr iEd )
    {
      for( ; iSt < iEd; ++iSt )
      {
        dst.push_back( new int(**iSt) );
      }
    }
  public:
    D() {};
    D( const C& lhs ) { _copy( v, lhs.v.begin(), lhs.v.end() ); }
    Vip v;
    void resize( unsigned int size )
    {
      if(size<v.size()) _clear( v.begin()+size-1, v.end() );
    }
    Vip_itr erase( Vip_itr itr )
    {
      if( ( itr != v.end() )&&( *itr ) ) delete *itr;
      return v.erase( itr );
    }
    void clear() { _clear( v.begin(), v.end() ); }
};

D v;
v.v.push_back(unique_ptr<C>(new C));

これでも抜けがあるかもしれない。実際、重複したポインター参照などを考慮していない。vectorをそのまま使えないことも問題があるだろう。

文芸的にはよいかもしれないが、実践的ではないと思う。