[C/C++] C++11でスマートポインタを使ってみたい

2013/07/17

こんにちは。きんくまです。

C++をやってます。
前にもやったことがあって、基本的な文法や使い方はわかっていたのだけど、細かいところを知らなくてあわあわしてます。

それで、オブジェクトをnewしたらdeleteが基本!みたいに覚えていたんですが、最近はスマートポインタというのがあるみたいです。

C++11という規格があって、そこに以前からあったBoostっていうライブラリで使われてた機能を盛り込んだみたい(違ってたらごめんなさい)。

Boostはなんかすごい便利みたいなんだけど、使ったことないからわかんないです、、。

で、スマートポインタです。

スマートポインタ

ここのページがすごくわかりやすかったです。

>> EZ-NET: C++11 でスマートポインタを使用する – C++ プログラミング

ポインタを自分でdeleteしなくても、所有者(owner)がいなくなったら勝手に破棄してくれるという。

、、ん?これってObjective-Cのリファレンスカウンタじゃ??
どっちが先かわかりませんが、そんな印象。

shared_ptrはObjective-CのARC前でいう autorelease
unique_ptrは所有者一人のretain
weak_ptrはassign

みたいな印象でした。

あとauto_ptrっていうのもあって、それは非推奨らしい。

それじゃあ、試しに挙動チェックしてみようと思い、ツリー構造をもたせた表示オブジェクトを作ってみました。

その中で、m_parentという親のスマートポインタをweak_ptrで持たせたかったんですが、そのためには自分自身のweak_ptrをプロパティに持つ必要があります。それで、どうやるのか調べてみたら、staticメソッドでやれば良いみたいでした。なるほど。weak_ptrなのは循環参照してもポインタを解放できるようにするためです。Objective-Cでのassign, weakと使い方はいっしょ。

>> 1. boost::weak_ptrを利用するケース

ソースです。ヘッダーファイル、実装ファイルに分けずに、main.cppに展開しちゃってますけど、サンプルなんですんません、、。


#include <iostream>
#include <memory>
#include <list>
#include <string>

class DisplayObject;
typedef std::unique_ptr<DisplayObject> DisplayObjectUp;
typedef std::shared_ptr<DisplayObject> DisplayObjectSp;
typedef std::weak_ptr<DisplayObject> DisplayObjectWp;

class DisplayObject{
public:
    
    static DisplayObjectSp CreateSp(const std::string name){
        DisplayObjectSp obj(new DisplayObject(name));
        obj->m_self = obj;
        return obj;
    }
    
    DisplayObject(const std::string name){
        m_name = name;
        std::cout << m_name << " is constructed" << std::endl;
    }
    
    ~DisplayObject(){
        std::cout << m_name << " is destructed" << std::endl;
    }
    
    std::string m_name;
    DisplayObjectWp m_self;
    DisplayObjectWp m_parent;
    std::list<DisplayObjectSp> m_children;
    
    void AddChild(const DisplayObjectSp &child){
        if(DisplayObjectSp myParent = child->m_parent.lock()){
            throw "child is already added";
            return;
        }
        child->m_parent = m_self;
        m_children.push_back(child);
        std::cout << child->m_name << " is added to " << m_self.lock()->m_name << std::endl;
    }
    
    void RemoveChild(const DisplayObjectSp &child){
        //auto is same as std::list<DisplayObjectSp>::iterator
        auto it = m_children.begin();
        while (it != m_children.end()) {
            if(*it == child){
                child->m_parent.reset();
                m_children.erase(it);
                std::cout << child->m_name << " is removed from " << m_self.lock()->m_name << std::endl;
            }
            it++;
        }
    }
    
    void Update(){
        //do something
        std::cout << m_name << " is updated" << std::endl;
        auto it = m_children.begin();
        while (it != m_children.end()) {
            (*it)->Update();
            it++;
        }
    }
};


int main(int argc, const char * argv[])
{
    DisplayObjectSp parent = DisplayObject::CreateSp("parent");
    {
        DisplayObjectSp child1 = DisplayObject::CreateSp("child 1");
        DisplayObjectSp child2 = DisplayObject::CreateSp("child 2");
        DisplayObjectSp grandChild = DisplayObject::CreateSp("grandchild");
        
        std::cout << std::endl << "----1" << std::endl;
        
        parent->AddChild(child1);
        parent->AddChild(child2);
        child1->AddChild(grandChild);
        
        std::cout << std::endl << "----2" << std::endl;
        
        parent->Update();
        
        std::cout << std::endl << "----3" << std::endl;
        
        parent->RemoveChild(child1);
    }
    std::cout << std::endl << "----4" << std::endl;
    
    return 0;
}

実行時の出力

parent is constructed
child 1 is constructed
child 2 is constructed
grandchild is constructed

----1
child 1 is added to parent
child 2 is added to parent
grandchild is added to child 1

----2
parent is updated
child 1 is updated
grandchild is updated
child 2 is updated

----3
child 1 is removed from parent
child 1 is destructed
grandchild is destructed

----4
parent is destructed
child 2 is destructed

ソース46行目autoというのが追加されたみたいです。iterator書くのに便利みたいです。

>> でらうま倶楽部 : 今日から始められる C++11 対応!!

その他の便利メソッドなども紹介されてます。

C++なかなかに歯ごたえがある言語ですが、けっこう面白いかも。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る