| 546 | |
| 547 | == 実践 shared_ptr == |
| 548 | |
| 549 | === ガベコレ === |
| 550 | |
| 551 | * GC のほうが適した問題領域も… |
| 552 | * 無いものはないので我慢 |
| 553 | |
| 554 | === カスタムデリータ === |
| 555 | |
| 556 | * 動的にリソースの解放方法を決める |
| 557 | * 所有者が居なくなったら呼ばれる (参照カウンタ) |
| 558 | * 同じ型でも確保、解放処理は異なる |
| 559 | * shared_ptr = カウンタ + デリータ |
| 560 | * 大事です |
| 561 | |
| 562 | === 具体例 === |
| 563 | |
| 564 | * boost::checked_deleter |
| 565 | * 単に delete する |
| 566 | * boost::checked_array_deleter |
| 567 | * delete[] |
| 568 | * 関数 (オブジェクト) なので何でもできます |
| 569 | * ログ仕込んだり… |
| 570 | * 典型例: ハンドルのクローズ |
| 571 | {{{ |
| 572 | HHOGE raw_handle = ::OpenHoge(...); |
| 573 | ::ReleaseHoge(raw_handle); |
| 574 | }}} |
| 575 | * 確実にハンドルをクローズするには…? |
| 576 | * 勝手に解放して下さい |
| 577 | {{{ |
| 578 | typedef |
| 579 | shared_ptr<remove_pointer<HHOGE>::type> |
| 580 | HogePtr; |
| 581 | HHOGE raw_handle = ::OpenHoge(...); |
| 582 | HogePtr hoge_h(raw_handle, ::CloseHoge); |
| 583 | }}} |
| 584 | |
| 585 | === リソース間の依存 === |
| 586 | |
| 587 | * 権利だけ主張する人もいます |
| 588 | {{{ |
| 589 | struct Legacy { |
| 590 | Buffer* buffer; // ちゃんと有効なバッファ指してね! |
| 591 | }; |
| 592 | }}} |
| 593 | * Legacy::buffer の管理は誰の責任? |
| 594 | * 所有権ちょいたし |
| 595 | {{{ |
| 596 | struct LegacyDeleter { |
| 597 | explicit LegacyDeleter(shared_ptr<Buffer> buffer) |
| 598 | : buffer(buffer) {} |
| 599 | void operator()(Legacy* ptr) const { delete ptr; } |
| 600 | shared_ptr<Buffer> buffer; // 所有 |
| 601 | }; |
| 602 | shared_ptr<Legacy> create(shared_ptr<Buffer> buffer) { |
| 603 | LegacyDeleter deleter(buffer); // デリータが所有 |
| 604 | shared_ptr<Legacy> ret(new legacy(), deleter); |
| 605 | ret->bufer = buffer.get(); |
| 606 | return ret; |
| 607 | }; |
| 608 | }}} |
| 609 | |
| 610 | === Null デリータ === |
| 611 | |
| 612 | * 何もしないデリータです。 |
| 613 | {{{ |
| 614 | struct NullDeleter { |
| 615 | void operator()(void*) const{} |
| 616 | }; |
| 617 | |
| 618 | void nullDeleter(void *){ |
| 619 | } |
| 620 | }}} |
| 621 | * 誰かが管理しているリソース |
| 622 | * コンテキストと生死を共にしている |
| 623 | * スタック、data領域、TLS ... |
| 624 | * 何らかの仕組みで管理されている |
| 625 | * 強調できるのが一番良いのですが… |
| 626 | * ポインタのフリしてるだけ |
| 627 | * reinterpret_cast<void *>(...) |
| 628 | {{{ |
| 629 | static vecter<int> vi; |
| 630 | shared_ptr<vector<int> > vi_ptr(&vi, NullDeleter()); |
| 631 | |
| 632 | void* val = reinterpret_cast<void*>(-1); |
| 633 | shared_ptr<void> val_ptr(val, NullDeleter()); |
| 634 | |
| 635 | shared_ptr<pair<int, int> > iip = ...; |
| 636 | shared_ptr<int> iptr(&iip->first, NullDeleter()); |
| 637 | }}} |
| 638 | * ところで (上記 3つ目) もし iip が有効じゃなかったら… |
| 639 | * 他の手を考えましょう。 |
| 640 | * boost もしくは 0x なら... |
| 641 | * 参照カウンタの共有! |
| 642 | * iip.use_count() == iptr.use_count() |
| 643 | * でも tr1 にはありません… |
| 644 | * tr1 なら Null デリータ + 延命 |
| 645 | {{{ |
| 646 | struct FirstDeleter { |
| 647 | explicet firstDeleter(shared_ptr<pair<int, int> > parent) |
| 648 | :parent(parent){} |
| 649 | void operator()(int*) const {}; |
| 650 | shared_ptr<pair<int, int> > parent; |
| 651 | }; |
| 652 | |
| 653 | === 応用 === |
| 654 | |
| 655 | * 参照はしたい、所有はしたくない、リソースが有効じゃなくても良い、でも安全だと嬉しい。 |
| 656 | * ↑お前は何を(ry |
| 657 | * どうしても所有してしまう |
| 658 | {{{ |
| 659 | weak_ptr<T> weak = ...; |
| 660 | shared_ptr<T> ptr = weak.lock(); |
| 661 | }}} |
| 662 | * リソース安全に扱うための仕組み |
| 663 | * 安全とか要らん |
| 664 | * これでもくらえ |
| 665 | {{{ |
| 666 | struct Deleter { |
| 667 | void operator()(T* ptr) const { not_onwer.reset(); ... } |
| 668 | shared_ptr<T> not_owner; |
| 669 | } deleter; |
| 670 | shared_ptr<T> owner(ptr, deleter); |
| 671 | deleter.not_owner.reset(owner.get(), NullDeleter()); |
| 672 | weak_ptr<T> not_owner_ref = deleter.not_owner; |
| 673 | }}} |
| 674 | * ex) HWND ... ウィンドウを生成したのとは別のスレッドで解放してはいけない |
| 675 | |
| 676 | === 注意 === |
| 677 | |
| 678 | * コンテキストに注意 |
| 679 | * デリータはどこでも呼び出される |
| 680 | |
| 681 | === みんな大好き void* === |
| 682 | |
| 683 | * 何でも参照できる魔法のポインタ型 |
| 684 | * ただのポインタ |
| 685 | * 参照なのか所有なのか? |
| 686 | * 有効なのか無効なのか? |
| 687 | * shared_ptr<void> |
| 688 | {{{ |
| 689 | vector<shared_ptr<void>> delay; |
| 690 | delay.push_back(make_shared<int>(1)); |
| 691 | delay.push_back(make_shared<string>("one")); |
| 692 | }}} |
| 693 | * 何でも入るぞ- |
| 694 | * カスタムデリータ-で正しく解放できる |
| 695 | * とりあえず寿命伸ばしたいときとかに |
| 696 | * 実践例: Blob |
| 697 | {{{ |
| 698 | struct Blob { |
| 699 | char* data; |
| 700 | size_t size; |
| 701 | shared_ptr<void> resource; |
| 702 | }; |
| 703 | }}} |
| 704 | {{{ |
| 705 | Blob createBlob(const vector<char>& v){ |
| 706 | shared_ptr<vector<char>> res(new vector<char>(v)); |
| 707 | return Blob(res->data().res->size(), res); |
| 708 | } |
| 709 | Blob createBlob(const string& str){ |
| 710 | shared_ptr<string> res(new string(str)); |
| 711 | return Blob(res->data().res->size(), res); |
| 712 | } |
| 713 | }}} |
| 714 | |
| 715 | === 複数のリソースを返す API === |
| 716 | |
| 717 | * unique_ptr -> shared_ptr |