2016-07-07 15 views
0

返さポインタを介しプライベートフィールドを入力します。ここではいくつかの可能なアプローチは、コメント欄でそれらについての私の疑問に、以下のとおりです。は、私はコンテナクラスを持っている

void initialize(Conatiner& container) { 
    MyItem item; 
    container.getItem() = &item; // Wrong, item gets destroyed at the end of the function 

    container.getItem() = new MyItem();   
    // This approach is filling my needs so far, but that doesn't necessarily 
    // mean it's correct. 
    // In particular, I'm not sure this approach properly removes the original item. 

    // Here I try to use placement new to reuse the memory pointed to by container.getitem 
    if (container.getItem()) { 
     MyItem* pItem = container.getItem(); 
     pItem->~MyItem(); 
     pItem = new (pItem) MyItem(); 
    } // but if the pointer is null, I don't have any memory to reassign! 
} 

は、ポインタを通じて取り込むフィールドを処理するための慣用的な方法はありますか?私はC++ 11の機能やBoostのような外部ライブラリにアクセスすることはできません。私はContainerのインターフェースも変更できません。

+3

は、それは危険なことがいくつかのケースでは、それは['のstdの賛成でC++ 11以降廃止されました:: unique_ptr'](http://en.cppreference.com/w/cpp/memory/unique_ptr)、 'std :: auto_ptr'はC++ 17標準から削除されます。 –

+1

パブリック関数を使って変更を許可しようとしているのであれば、なぜそれを非公開にするのでしょうか?とにかく、 '* container.getItem()= MyItem();'はどうでしょうか? –

+2

また、 'getItem'は値*によって格納されたポインタ*を返しますので、左側の' getItem'を使って割り当てを行うことはできません。おそらく、例えば。 '* container.getItem()= MyItem()'はうまくいくはずです。それはスマートポインタの "所有権"モデルをバイパスします。 –

答えて

2

initializeContainer()は、単に通常のチャネルを介してContainer::mItem部材を設定するアクセス権を持っていません。 mItemが保持する​​ポインターが返され、そのポインターからmItemにアクセスできないため、Container::getItem()を使用してそのアクセスを提供することはできません。

はあなたがいずれかの方法で、mItemへのアクセスを許可するようにContainerを変更する必要があります。

class Container { 
private: 
    std::auto_ptr<MyItem> mItem; 
public: 
    MyItem* getItem() { return mItem.get(); } 
    void setItem(const MyItem &item) { mItem.reset(new MyItem(item)); } 
}; 

void initialize(Container& container) { 
    MyItem item; 
    container.setItem(item); 
} 
  • 宣言:

    1. mItemを設定し、公開方法Containerを与え、その方法initializeContainer()コールを持っていますinitializeContainer()friendContainerとすると、privateのメンバーに直接アクセスできます:

      class Container { 
      private: 
          std::auto_ptr<MyItem> mItem; 
      public: 
          MyItem* getItem() { return mItem.get(); } 
      
          friend void initialize(Container&); 
      }; 
      
      void initialize(Container& container) { 
          container.mItem.reset(new MyItem); 
      } 
      
    2. 完全initializeContainer()を取り除き、代わりにContainer公共初期化メソッドを与えるガイド:

      class Container { 
      private: 
          std::auto_ptr<MyItem> mItem; 
      public: 
          void init() { mItem.reset(new MyItem); } 
          MyItem* getItem() { return mItem.get(); } 
      }; 
      
      Container c; 
      c.init(); 
      

    は、ポインタを通じて取り込むフィールドを処理するための慣用的な方法はありますか?

    ないあなたがいない、それを行うにしようとしている方法。 Containerオブジェクト自体に関連していないポインタを使用しようとしています。したがって、最初にContainerオブジェクトを指していないので、Containerオブジェクトのメンバーにアクセスするためにそのポインタを使用することはできません。

    私はまた、コンテナのインタフェースを変更することはできませんしています。

    あなたがしようとしているのはインターフェイスの変更が必要なので、あなたは運が悪いです。あなたは醜いポインタハック、例えば使用しない限り:あなたの意図はmItem自体を変更することではなく、単純に(再)にあれば、一方

    class Container { 
    private: 
        std::auto_ptr<MyItem> mItem; 
    public: 
        MyItem* getItem() { return mItem.get(); } 
    }; 
    
    void initialize(Container& container) { 
        unsigned char *p = reinterpret_cast<unsigned char*>(&container); 
        std::auto_ptr<MyItem> *ap = reinterpret_cast<std::auto_ptr<MyItem>*>(p + offsetof(Container, mItem)); 
        ap->reset(new MyItem); 
    } 
    

    mItemがすでにあることMyItemオブジェクトを初期化します保持、あなた、そのためgetItem()を使用することができますが、MyItemオブジェクトが事前に作成されている場合にのみ:

    あなたが012を許可しないことによって確保することができます
    void initialize(Container &container) { 
        MyItem *item = container.getItem(); 
        if (item) *item = MyItem(); 
    } 
    

    を最初の場所でNULLポインタを保持する: `のstd :: auto_ptr`使用を中止してください

    class Container { 
    private: 
        std::auto_ptr<MyItem> mItem; 
    public: 
        Container() : mItem(new MyItem) {} 
        Container(const Container &src) : mItem(new MyItem(src.getItem())) {} 
        Container& operator=(const Container &rhs) { mItem.reset(new MyItem(rhs.getItem())); return *this; } 
    
        MyItem& getItem() { return *mItem.get(); } 
    }; 
    
  • 1

    以下は、クラスContainerとnot-nullポインタの変更を意味します。

    普通ポインタ(ないauto)を使用して、例えば、参照によりリターン:

    #include <iostream> 
    
    class MyItem{ 
    private: 
        int a; 
    public: 
        ~MyItem(){std::cout<<"My item destroyed!\n";} 
        MyItem(int _a):a(_a){}; 
        int getValue(){return a;} 
    }; 
    
    class Container { 
    public: 
        MyItem & getItem() { return *(mItem); } 
    private: 
        MyItem* mItem; 
    }; 
    
    void initialize(Container& container) { 
        std::cout<<"New item\n"; 
        MyItem* p2=new MyItem(25); 
        std::cout<<"Getting item\n"; 
        MyItem &p1 = container.getItem(); 
        std::cout<<"Copying\n"; 
        p1=*p2; // should define your own operator = for complex MyItem type 
        delete p2; 
        std::cout<<"New item\n"; 
        MyItem* p3=new MyItem(5); 
        std::cout<<"Copying\n"; 
        p1=*p3; 
        delete p3; 
    } 
    
    int main() 
    { 
        Container c; 
        initialize(c); 
        std::cout<<c.getItem().getValue()<<std::endl; 
        return 0; 
    } 
    

    出力:ポインタの代わりに参照すると

    New item 
    Getting item 
    Copying 
    My item destroyed! 
    New item 
    Copying 
    My item destroyed! 
    5 
    

    (のみ関連するコード・ブロックを変更します)。

    ... 
        MyItem* getItem() { return mItem; } 
        ... 
        MyItem *p1 = container.getItem(); 
        std::cout<<"Copying\n"; 
        *p1=*p2; 
        ... (the same with p3) 
        ... 
        std::cout<<c.getItem()->getValue()<<std::endl; 
    

    以下の答えはC++11です。

    参照によってunique_ptrにアクセスし、移動意味を に変更すると、スマートポインタが指すオブジェクトの値を変更できます。

    #include <iostream> 
    #include <memory> 
    
    class MyItem{ 
    private: 
        int a; 
    public: 
        ~MyItem(){std::cout<<"My item destroyed!\n";}  
        MyItem(int _a):a(_a){}; 
        int getValue(){return a;} 
    }; 
    
    class Container { 
    public: 
        std::unique_ptr<MyItem> & getItem() { return mItem; } 
    private: 
        std::unique_ptr<MyItem> mItem; 
    }; 
    
    void initialize(Container& container) { 
        std::unique_ptr<MyItem> p2(new MyItem(5)); 
        std::unique_ptr<MyItem> &p1 = container.getItem(); 
        std::cout<<"Copying\n"; 
        p1 = std::move(p2); 
        std::unique_ptr<MyItem> p3(new MyItem(20)); 
        std::cout<<"Copying\n"; 
        p1 = std::move(p3); 
    } 
    
    int main() 
    { 
        Container c; 
        initialize(c); 
        std::cout<<c.getItem()->getValue()<<std::endl; 
        return 0; 
    } 
    
    関連する問題